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  wxT( "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( wxT( "%.4g" ),
980  GetOrientationDegrees() ) );
981 
982  msg.Printf( _( "Footprint: %s" ), m_fpid.GetUniStringLibId() );
983  msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
984  : m_3D_Drawings.front().m_Filename );
985  aList.emplace_back( msg, msg2 );
986 
987  msg.Printf( _( "Doc: %s" ), m_doc );
988  msg2.Printf( _( "Keywords: %s" ), m_keywords );
989  aList.emplace_back( msg, msg2 );
990 }
991 
992 
993 bool FOOTPRINT::IsOnLayer( PCB_LAYER_ID aLayer ) const
994 {
995  // If we have any pads, fall back on normal checking
996  if( !m_pads.empty() )
997  return m_layer == aLayer;
998 
999  // No pads? Check if this entire footprint exists on the given layer
1000  for( FP_ZONE* zone : m_fp_zones )
1001  {
1002  if( !zone->IsOnLayer( aLayer ) )
1003  return false;
1004  }
1005 
1006  for( BOARD_ITEM* item : m_drawings )
1007  {
1008  if( !item->IsOnLayer( aLayer ) )
1009  return false;
1010  }
1011 
1012  return true;
1013 }
1014 
1015 
1016 bool FOOTPRINT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
1017 {
1018  EDA_RECT rect = GetBoundingBox( false, false );
1019  return rect.Inflate( aAccuracy ).Contains( aPosition );
1020 }
1021 
1022 
1023 bool FOOTPRINT::HitTestAccurate( const wxPoint& aPosition, int aAccuracy ) const
1024 {
1025  return GetBoundingHull().Collide( aPosition, aAccuracy );
1026 }
1027 
1028 
1029 bool FOOTPRINT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
1030 {
1031  EDA_RECT arect = aRect;
1032  arect.Inflate( aAccuracy );
1033 
1034  if( aContained )
1035  {
1036  return arect.Contains( GetBoundingBox( false, false ) );
1037  }
1038  else
1039  {
1040  // If the rect does not intersect the bounding box, skip any tests
1041  if( !aRect.Intersects( GetBoundingBox( false, false ) ) )
1042  return false;
1043 
1044  // The empty footprint dummy rectangle intersects the selection area.
1045  if( m_pads.empty() && m_fp_zones.empty() && m_drawings.empty() )
1046  return GetBoundingBox( true, false ).Intersects( arect );
1047 
1048  // Determine if any elements in the FOOTPRINT intersect the rect
1049  for( PAD* pad : m_pads )
1050  {
1051  if( pad->HitTest( arect, false, 0 ) )
1052  return true;
1053  }
1054 
1055  for( FP_ZONE* zone : m_fp_zones )
1056  {
1057  if( zone->HitTest( arect, false, 0 ) )
1058  return true;
1059  }
1060 
1061  for( BOARD_ITEM* item : m_drawings )
1062  {
1063  if( item->Type() != PCB_FP_TEXT_T && item->HitTest( arect, false, 0 ) )
1064  return true;
1065  }
1066 
1067  // Groups are not hit-tested; only their members
1068 
1069  // No items were hit
1070  return false;
1071  }
1072 }
1073 
1074 
1075 PAD* FOOTPRINT::FindPadByNumber( const wxString& aPadNumber, PAD* aSearchAfterMe ) const
1076 {
1077  bool can_select = aSearchAfterMe ? false : true;
1078 
1079  for( PAD* pad : m_pads )
1080  {
1081  if( !can_select && pad == aSearchAfterMe )
1082  {
1083  can_select = true;
1084  continue;
1085  }
1086 
1087  if( can_select && pad->GetNumber() == aPadNumber )
1088  return pad;
1089  }
1090 
1091  return nullptr;
1092 }
1093 
1094 
1095 PAD* FOOTPRINT::GetPad( const wxPoint& aPosition, LSET aLayerMask )
1096 {
1097  for( PAD* pad : m_pads )
1098  {
1099  // ... and on the correct layer.
1100  if( !( pad->GetLayerSet() & aLayerMask ).any() )
1101  continue;
1102 
1103  if( pad->HitTest( aPosition ) )
1104  return pad;
1105  }
1106 
1107  return nullptr;
1108 }
1109 
1110 
1112 {
1113  PAD* topLeftPad = m_pads.front();
1114 
1115  for( PAD* p : m_pads )
1116  {
1117  wxPoint pnt = p->GetPosition(); // GetPosition() returns the center of the pad
1118 
1119  if( ( pnt.x < topLeftPad->GetPosition().x ) ||
1120  ( topLeftPad->GetPosition().x == pnt.x && pnt.y < topLeftPad->GetPosition().y ) )
1121  {
1122  topLeftPad = p;
1123  }
1124  }
1125 
1126  return topLeftPad;
1127 }
1128 
1129 
1130 unsigned FOOTPRINT::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1131 {
1132  if( aIncludeNPTH )
1133  return m_pads.size();
1134 
1135  unsigned cnt = 0;
1136 
1137  for( PAD* pad : m_pads )
1138  {
1139  if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1140  continue;
1141 
1142  cnt++;
1143  }
1144 
1145  return cnt;
1146 }
1147 
1148 
1149 unsigned FOOTPRINT::GetUniquePadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1150 {
1151  std::set<wxString> usedNumbers;
1152 
1153  // Create a set of used pad numbers
1154  for( PAD* pad : m_pads )
1155  {
1156  // Skip pads not on copper layers (used to build complex
1157  // solder paste shapes for instance)
1158  if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none() )
1159  continue;
1160 
1161  // Skip pads with no name, because they are usually "mechanical"
1162  // pads, not "electrical" pads
1163  if( pad->GetNumber().IsEmpty() )
1164  continue;
1165 
1166  if( !aIncludeNPTH )
1167  {
1168  // skip NPTH
1169  if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1170  continue;
1171  }
1172 
1173  usedNumbers.insert( pad->GetNumber() );
1174  }
1175 
1176  return usedNumbers.size();
1177 }
1178 
1179 
1181 {
1182  if( nullptr == a3DModel )
1183  return;
1184 
1185  if( !a3DModel->m_Filename.empty() )
1186  m_3D_Drawings.push_back( *a3DModel );
1187 }
1188 
1189 
1190 // see footprint.h
1191 SEARCH_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
1192 {
1193  KICAD_T stype;
1195  const KICAD_T* p = scanTypes;
1196  bool done = false;
1197 
1198 #if 0 && defined(DEBUG)
1199  std::cout << GetClass().mb_str() << ' ';
1200 #endif
1201 
1202  while( !done )
1203  {
1204  stype = *p;
1205 
1206  switch( stype )
1207  {
1208  case PCB_FOOTPRINT_T:
1209  result = inspector( this, testData ); // inspect me
1210  ++p;
1211  break;
1212 
1213  case PCB_PAD_T:
1214  result = IterateForward<PAD*>( m_pads, inspector, testData, p );
1215  ++p;
1216  break;
1217 
1218  case PCB_FP_ZONE_T:
1219  result = IterateForward<FP_ZONE*>( m_fp_zones, inspector, testData, p );
1220  ++p;
1221  break;
1222 
1223  case PCB_FP_TEXT_T:
1224  result = inspector( m_reference, testData );
1225 
1226  if( result == SEARCH_RESULT::QUIT )
1227  break;
1228 
1229  result = inspector( m_value, testData );
1230 
1231  if( result == SEARCH_RESULT::QUIT )
1232  break;
1233 
1234  // Intentionally fall through since m_Drawings can hold PCB_FP_SHAPE_T also
1236 
1237  case PCB_FP_SHAPE_T:
1238  result = IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, p );
1239 
1240  // skip over any types handled in the above call.
1241  for( ; ; )
1242  {
1243  switch( stype = *++p )
1244  {
1245  case PCB_FP_TEXT_T:
1246  case PCB_FP_SHAPE_T:
1247  continue;
1248 
1249  default:
1250  ;
1251  }
1252 
1253  break;
1254  }
1255 
1256  break;
1257 
1258  case PCB_GROUP_T:
1259  result = IterateForward<PCB_GROUP*>( m_fp_groups, inspector, testData, p );
1260  ++p;
1261  break;
1262 
1263  default:
1264  done = true;
1265  break;
1266  }
1267 
1268  if( result == SEARCH_RESULT::QUIT )
1269  break;
1270  }
1271 
1272  return result;
1273 }
1274 
1275 
1276 wxString FOOTPRINT::GetSelectMenuText( EDA_UNITS aUnits ) const
1277 {
1278  wxString reference = GetReference();
1279 
1280  if( reference.IsEmpty() )
1281  reference = _( "<no reference designator>" );
1282 
1283  return wxString::Format( _( "Footprint %s" ), reference );
1284 }
1285 
1286 
1288 {
1289  return BITMAPS::module;
1290 }
1291 
1292 
1294 {
1295  return new FOOTPRINT( *this );
1296 }
1297 
1298 
1299 void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM*)>& aFunction ) const
1300 {
1301  try
1302  {
1303  for( PAD* pad : m_pads )
1304  aFunction( static_cast<BOARD_ITEM*>( pad ) );
1305 
1306  for( FP_ZONE* zone : m_fp_zones )
1307  aFunction( static_cast<FP_ZONE*>( zone ) );
1308 
1309  for( PCB_GROUP* group : m_fp_groups )
1310  aFunction( static_cast<PCB_GROUP*>( group ) );
1311 
1312  for( BOARD_ITEM* drawing : m_drawings )
1313  aFunction( static_cast<BOARD_ITEM*>( drawing ) );
1314 
1315  aFunction( static_cast<BOARD_ITEM*>( m_reference ) );
1316  aFunction( static_cast<BOARD_ITEM*>( m_value ) );
1317  }
1318  catch( std::bad_function_call& )
1319  {
1320  wxFAIL_MSG( wxT( "Error running FOOTPRINT::RunOnChildren" ) );
1321  }
1322 }
1323 
1324 
1325 void FOOTPRINT::GetAllDrawingLayers( int aLayers[], int& aCount, bool aIncludePads ) const
1326 {
1327  std::unordered_set<int> layers;
1328 
1329  for( BOARD_ITEM* item : m_drawings )
1330  layers.insert( static_cast<int>( item->GetLayer() ) );
1331 
1332  if( aIncludePads )
1333  {
1334  for( PAD* pad : m_pads )
1335  {
1336  int pad_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], pad_layers_count;
1337  pad->ViewGetLayers( pad_layers, pad_layers_count );
1338 
1339  for( int i = 0; i < pad_layers_count; i++ )
1340  layers.insert( pad_layers[i] );
1341  }
1342  }
1343 
1344  aCount = layers.size();
1345  int i = 0;
1346 
1347  for( int layer : layers )
1348  aLayers[i++] = layer;
1349 }
1350 
1351 
1352 void FOOTPRINT::ViewGetLayers( int aLayers[], int& aCount ) const
1353 {
1354  aCount = 2;
1355  aLayers[0] = LAYER_ANCHOR;
1356 
1357  switch( m_layer )
1358  {
1359  default:
1360  wxASSERT_MSG( false, wxT( "Illegal layer" ) ); // do you really have footprints placed
1361  // on other layers?
1363 
1364  case F_Cu:
1365  aLayers[1] = LAYER_MOD_FR;
1366  break;
1367 
1368  case B_Cu:
1369  aLayers[1] = LAYER_MOD_BK;
1370  break;
1371  }
1372 
1373  // If there are no pads, and only drawings on a silkscreen layer, then report the silkscreen
1374  // layer as well so that the component can be edited with the silkscreen layer
1375  bool f_silk = false, b_silk = false, non_silk = false;
1376 
1377  for( BOARD_ITEM* item : m_drawings )
1378  {
1379  if( item->GetLayer() == F_SilkS )
1380  f_silk = true;
1381  else if( item->GetLayer() == B_SilkS )
1382  b_silk = true;
1383  else
1384  non_silk = true;
1385  }
1386 
1387  if( ( f_silk || b_silk ) && !non_silk && m_pads.empty() )
1388  {
1389  if( f_silk )
1390  aLayers[ aCount++ ] = F_SilkS;
1391 
1392  if( b_silk )
1393  aLayers[ aCount++ ] = B_SilkS;
1394  }
1395 }
1396 
1397 
1398 double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1399 {
1400  int layer = ( m_layer == F_Cu ) ? LAYER_MOD_FR :
1402 
1403  // Currently this is only pertinent for the anchor layer; everything else is drawn from the
1404  // children.
1405  // The "good" value is experimentally chosen.
1406  #define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY 1.5
1407 
1408  if( aView->IsLayerVisible( layer ) )
1410 
1411  return std::numeric_limits<double>::max();
1412 }
1413 
1414 
1416 {
1417  EDA_RECT area = GetBoundingBox( true, true );
1418 
1419  // Add the Clearance shape size: (shape around the pads when the clearance is shown. Not
1420  // optimized, but the draw cost is small (perhaps smaller than optimization).
1421  const BOARD* board = GetBoard();
1422 
1423  if( board )
1424  {
1425  int biggest_clearance = board->GetDesignSettings().GetBiggestClearanceValue();
1426  area.Inflate( biggest_clearance );
1427  }
1428 
1429  return area;
1430 }
1431 
1432 
1433 bool FOOTPRINT::IsLibNameValid( const wxString & aName )
1434 {
1435  const wxChar * invalids = StringLibNameInvalidChars( false );
1436 
1437  if( aName.find_first_of( invalids ) != std::string::npos )
1438  return false;
1439 
1440  return true;
1441 }
1442 
1443 
1444 const wxChar* FOOTPRINT::StringLibNameInvalidChars( bool aUserReadable )
1445 {
1446  // This list of characters is also duplicated in validators.cpp and
1447  // lib_id.cpp
1448  // TODO: Unify forbidden character lists
1449  static const wxChar invalidChars[] = wxT("%$<>\t\n\r\"\\/:");
1450  static const wxChar invalidCharsReadable[] = wxT("% $ < > 'tab' 'return' 'line feed' \\ \" / :");
1451 
1452  if( aUserReadable )
1453  return invalidCharsReadable;
1454  else
1455  return invalidChars;
1456 }
1457 
1458 
1459 void FOOTPRINT::Move( const wxPoint& aMoveVector )
1460 {
1461  wxPoint newpos = m_pos + aMoveVector;
1462  SetPosition( newpos );
1463 }
1464 
1465 
1466 void FOOTPRINT::Rotate( const wxPoint& aRotCentre, double aAngle )
1467 {
1468  double orientation = GetOrientation();
1469  double newOrientation = orientation + aAngle;
1470  wxPoint newpos = m_pos;
1471  RotatePoint( &newpos, aRotCentre, aAngle );
1472  SetPosition( newpos );
1473  SetOrientation( newOrientation );
1474 
1475  m_reference->KeepUpright( orientation, newOrientation );
1476  m_value->KeepUpright( orientation, newOrientation );
1477 
1478  for( BOARD_ITEM* item : m_drawings )
1479  {
1480  if( item->Type() == PCB_FP_TEXT_T )
1481  static_cast<FP_TEXT*>( item )->KeepUpright( orientation, newOrientation );
1482  }
1483 
1488 }
1489 
1490 
1491 void FOOTPRINT::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
1492 {
1493  // Move footprint to its final position:
1494  wxPoint finalPos = m_pos;
1495 
1496  // Now Flip the footprint.
1497  // Flipping a footprint is a specific transform: it is not mirrored like a text.
1498  // We have to change the side, and ensure the footprint rotation is modified according to the
1499  // transform, because this parameter is used in pick and place files, and when updating the
1500  // footprint from library.
1501  // When flipped around the X axis (Y coordinates changed) orientation is negated
1502  // When flipped around the Y axis (X coordinates changed) orientation is 180 - old orient.
1503  // Because it is specific to a footprint, we flip around the X axis, and after rotate 180 deg
1504 
1505  MIRROR( finalPos.y, aCentre.y );
1506 
1507  SetPosition( finalPos );
1508 
1509  // Flip layer
1510  SetLayer( FlipLayer( GetLayer() ) );
1511 
1512  // Reverse mirror orientation.
1513  m_orient = -m_orient;
1514 
1516 
1517  // Mirror pads to other side of board.
1518  for( PAD* pad : m_pads )
1519  pad->Flip( m_pos, false );
1520 
1521  // Mirror zones to other side of board.
1522  for( ZONE* zone : m_fp_zones )
1523  zone->Flip( m_pos, false );
1524 
1525  // Mirror reference and value.
1526  m_reference->Flip( m_pos, false );
1527  m_value->Flip( m_pos, false );
1528 
1529  // Reverse mirror footprint graphics and texts.
1530  for( BOARD_ITEM* item : m_drawings )
1531  {
1532  switch( item->Type() )
1533  {
1534  case PCB_FP_SHAPE_T:
1535  static_cast<FP_SHAPE*>( item )->Flip( m_pos, false );
1536  break;
1537 
1538  case PCB_FP_TEXT_T:
1539  static_cast<FP_TEXT*>( item )->Flip( m_pos, false );
1540  break;
1541 
1542  default:
1543  wxMessageBox( wxT( "FOOTPRINT::Flip() error: Unknown Draw Type" ) );
1544  break;
1545  }
1546  }
1547 
1548  // Now rotate 180 deg if required
1549  if( aFlipLeftRight )
1550  Rotate( aCentre, 1800.0 );
1551 
1555 
1556  m_cachedHull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos );
1557 
1559 }
1560 
1561 
1562 void FOOTPRINT::SetPosition( const wxPoint& aPos )
1563 {
1564  wxPoint delta = aPos - m_pos;
1565 
1566  m_pos += delta;
1567 
1568  m_reference->EDA_TEXT::Offset( delta );
1569  m_value->EDA_TEXT::Offset( delta );
1570 
1571  for( PAD* pad : m_pads )
1572  pad->SetPosition( pad->GetPosition() + delta );
1573 
1574  for( ZONE* zone : m_fp_zones )
1575  zone->Move( delta );
1576 
1577  for( BOARD_ITEM* item : m_drawings )
1578  {
1579  switch( item->Type() )
1580  {
1581  case PCB_FP_SHAPE_T:
1582  {
1583  FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1584  shape->SetDrawCoord();
1585  break;
1586  }
1587 
1588  case PCB_FP_TEXT_T:
1589  {
1590  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1591  text->EDA_TEXT::Offset( delta );
1592  break;
1593  }
1594 
1595  default:
1596  wxMessageBox( wxT( "Draw type undefined." ) );
1597  break;
1598  }
1599  }
1600 
1604  m_cachedHull.Move( delta );
1605 }
1606 
1607 
1608 void FOOTPRINT::MoveAnchorPosition( const wxPoint& aMoveVector )
1609 {
1610  /* Move the reference point of the footprint
1611  * the footprints elements (pads, outlines, edges .. ) are moved
1612  * but:
1613  * - the footprint position is not modified.
1614  * - the relative (local) coordinates of these items are modified
1615  * - Draw coordinates are updated
1616  */
1617 
1618 
1619  // Update (move) the relative coordinates relative to the new anchor point.
1620  wxPoint moveVector = aMoveVector;
1621  RotatePoint( &moveVector, -GetOrientation() );
1622 
1623  // Update of the reference and value.
1624  m_reference->SetPos0( m_reference->GetPos0() + moveVector );
1626  m_value->SetPos0( m_value->GetPos0() + moveVector );
1627  m_value->SetDrawCoord();
1628 
1629  // Update the pad local coordinates.
1630  for( PAD* pad : m_pads )
1631  {
1632  pad->SetPos0( pad->GetPos0() + moveVector );
1633  pad->SetDrawCoord();
1634  }
1635 
1636  // Update the draw element coordinates.
1637  for( BOARD_ITEM* item : GraphicalItems() )
1638  {
1639  switch( item->Type() )
1640  {
1641  case PCB_FP_SHAPE_T:
1642  {
1643  FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1644  shape->Move( moveVector );
1645  }
1646  break;
1647 
1648  case PCB_FP_TEXT_T:
1649  {
1650  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1651  text->SetPos0( text->GetPos0() + moveVector );
1652  text->SetDrawCoord();
1653  }
1654  break;
1655 
1656  default:
1657  break;
1658  }
1659  }
1660 
1661  // Update the keepout zones
1662  for( ZONE* zone : Zones() )
1663  {
1664  zone->Move( moveVector );
1665  }
1666 
1667  // Update the 3D models
1668  for( FP_3DMODEL& model : Models() )
1669  {
1670  model.m_Offset.x += Iu2Millimeter( moveVector.x );
1671  model.m_Offset.y -= Iu2Millimeter( moveVector.y );
1672  }
1673 
1674  m_cachedBoundingBox.Move( moveVector );
1675  m_cachedVisibleBBox.Move( moveVector );
1676  m_cachedTextExcludedBBox.Move( moveVector );
1677  m_cachedHull.Move( moveVector );
1678 }
1679 
1680 
1681 void FOOTPRINT::SetOrientation( double aNewAngle )
1682 {
1683  double angleChange = aNewAngle - m_orient; // change in rotation
1684 
1685  NORMALIZE_ANGLE_180( aNewAngle );
1686 
1687  m_orient = aNewAngle;
1688 
1689  for( PAD* pad : m_pads )
1690  {
1691  pad->SetOrientation( pad->GetOrientation() + angleChange );
1692  pad->SetDrawCoord();
1693  }
1694 
1695  for( ZONE* zone : m_fp_zones )
1696  {
1697  zone->Rotate( GetPosition(), angleChange );
1698  }
1699 
1700  // Update of the reference and value.
1702  m_value->SetDrawCoord();
1703 
1704  // Displace contours and text of the footprint.
1705  for( BOARD_ITEM* item : m_drawings )
1706  {
1707  if( item->Type() == PCB_FP_SHAPE_T )
1708  {
1709  static_cast<FP_SHAPE*>( item )->SetDrawCoord();
1710  }
1711  else if( item->Type() == PCB_FP_TEXT_T )
1712  {
1713  static_cast<FP_TEXT*>( item )->SetDrawCoord();
1714  }
1715  }
1716 
1720 
1721  m_cachedHull.Rotate( -DECIDEG2RAD( angleChange ), GetPosition() );
1722 }
1723 
1724 
1726 {
1727  FOOTPRINT* dupe = static_cast<FOOTPRINT*>( BOARD_ITEM::Duplicate() );
1728 
1729  dupe->RunOnChildren( [&]( BOARD_ITEM* child )
1730  {
1731  const_cast<KIID&>( child->m_Uuid ) = KIID();
1732  });
1733 
1734  return 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( wxT( "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( wxT( "%s%d" ), prefix, num ) ) )
1837  num++;
1838 
1839  return wxString::Format( wxT( "%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, FLASHING aFlash ) 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, aFlash )->Clone() );
2029 
2030  for( BOARD_ITEM* item : GraphicalItems() )
2031  {
2032  if( item->Type() == PCB_FP_SHAPE_T )
2033  shape->AddShape( item->GetEffectiveShape( aLayer, aFlash )->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 = wxT( "(" ) + msg + wxT( ")" );
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->GetDrillSizeY() < 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( !pad->FlashLayer( aLayer ) )
2218  continue;
2219 
2220  wxSize clearance( aClearance, aClearance );
2221 
2222  switch( aLayer )
2223  {
2224  case F_Cu:
2225  if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
2226  continue;
2227 
2228  if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
2229  continue;
2230 
2231  break;
2232 
2233  case B_Cu:
2234  if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
2235  continue;
2236 
2237  if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
2238  continue;
2239 
2240  break;
2241 
2242  case F_Mask:
2243  case B_Mask:
2244  clearance.x += pad->GetSolderMaskMargin();
2245  clearance.y += pad->GetSolderMaskMargin();
2246  break;
2247 
2248  case F_Paste:
2249  case B_Paste:
2250  clearance += pad->GetSolderPasteMargin();
2251  break;
2252 
2253  default:
2254  break;
2255  }
2256 
2257  // Our standard TransformShapeWithClearanceToPolygon() routines can't handle differing
2258  // x:y clearance values (which get generated when a relative paste margin is used with
2259  // an oblong pad). So we apply this huge hack and fake a larger pad to run the transform
2260  // on.
2261  // Of course being a hack it falls down when dealing with custom shape pads (where the
2262  // size is only the size of the anchor), so for those we punt and just use clearance.x.
2263 
2264  if( ( clearance.x < 0 || clearance.x != clearance.y )
2265  && pad->GetShape() != PAD_SHAPE::CUSTOM )
2266  {
2267  wxSize dummySize = pad->GetSize() + clearance + clearance;
2268 
2269  if( dummySize.x <= 0 || dummySize.y <= 0 )
2270  continue;
2271 
2272  PAD dummy( *pad );
2273  dummy.SetSize( dummySize );
2274  dummy.TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0,
2275  aMaxError, aErrorLoc );
2276  }
2277  else
2278  {
2279  pad->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, clearance.x,
2280  aMaxError, aErrorLoc );
2281  }
2282  }
2283 }
2284 
2285 
2287  PCB_LAYER_ID aLayer, int aClearance,
2288  int aError, ERROR_LOC aErrorLoc,
2289  bool aIncludeText,
2290  bool aIncludeShapes ) const
2291 {
2292  std::vector<FP_TEXT*> texts; // List of FP_TEXT to convert
2293 
2294  for( BOARD_ITEM* item : GraphicalItems() )
2295  {
2296  if( item->Type() == PCB_FP_TEXT_T && aIncludeText )
2297  {
2298  FP_TEXT* text = static_cast<FP_TEXT*>( item );
2299 
2300  if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer && text->IsVisible() )
2301  texts.push_back( text );
2302  }
2303 
2304  if( item->Type() == PCB_FP_SHAPE_T && aIncludeShapes )
2305  {
2306  const FP_SHAPE* outline = static_cast<FP_SHAPE*>( item );
2307 
2308  if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer )
2309  {
2310  outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0,
2311  aError, aErrorLoc );
2312  }
2313  }
2314  }
2315 
2316  if( aIncludeText )
2317  {
2318  if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
2319  texts.push_back( &Reference() );
2320 
2321  if( Value().GetLayer() == aLayer && Value().IsVisible() )
2322  texts.push_back( &Value() );
2323  }
2324 
2325  for( const FP_TEXT* text : texts )
2326  {
2327  text->TransformTextShapeWithClearanceToPolygon( aCornerBuffer, aLayer, aClearance,
2328  aError, aErrorLoc );
2329  }
2330 }
2331 
2332 
2333 static struct FOOTPRINT_DESC
2334 {
2336  {
2338 
2339  if( layerEnum.Choices().GetCount() == 0 )
2340  {
2341  layerEnum.Undefined( UNDEFINED_LAYER );
2342 
2343  for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
2344  layerEnum.Map( *seq, LSET::Name( *seq ) );
2345  }
2346 
2347  wxPGChoices fpLayers; // footprints might be placed only on F.Cu & B.Cu
2348  fpLayers.Add( LSET::Name( F_Cu ), F_Cu );
2349  fpLayers.Add( LSET::Name( B_Cu ), B_Cu );
2350 
2357 
2358  auto layer = new PROPERTY_ENUM<FOOTPRINT, PCB_LAYER_ID, BOARD_ITEM>( _HKI( "Layer" ),
2360  layer->SetChoices( fpLayers );
2361  propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
2362 
2363  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Reference" ),
2365  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Value" ),
2367  propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Orientation" ),
2370  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Clearance Override" ),
2373  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Solderpaste Margin Override" ),
2376  propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Solderpaste Margin Ratio Override" ),
2379  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Thermal Relief Width" ),
2382  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Thermal Relief Gap" ),
2385  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Library ID" ),
2387  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Description" ),
2389  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Keywords" ),
2391  // TODO zone connection
2392  }
2393 } _FOOTPRINT_DESC;
void SetReference(const wxString &aReference)
Definition: footprint.h:475
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:772
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:297
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:1398
const wxString & GetDescription() const
Definition: footprint.h:201
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:760
int GetWidth() const
Definition: eda_shape.h:98
#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:1276
#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:993
const wxString & GetValue() const
Definition: footprint.h:488
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
Definition: footprint.cpp:1130
ZONE_CONNECTION m_zoneConnection
Definition: footprint.h:767
double m_localSolderPasteMarginRatio
Definition: footprint.h:773
SHAPE_POLY_SET m_poly_courtyard_back
Definition: footprint.h:790
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:164
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:217
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:294
double m_orient
Definition: footprint.h:740
const wxString GetFPIDAsString() const
Definition: footprint.h:198
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:778
Collection of utility functions for component reference designators (refdes)
int GetWidth() const
Definition: eda_rect.h:118
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
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:208
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:130
double Area()
Count the number of arc shapes present.
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: footprint.h:228
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:742
show footprints on back
Definition: layer_ids.h:216
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
int m_visibleBBoxCacheTimeStamp
Definition: footprint.h:761
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:236
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:1287
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:781
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:1180
FP_TEXT & Value()
read/write accessors:
Definition: footprint.h:502
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:743
PAD * GetTopLeftPad()
Definition: footprint.cpp:1111
void SetThermalWidth(int aWidth)
Definition: footprint.h:233
void SetDescription(const wxString &aDoc)
Definition: footprint.h:202
int m_arflag
Definition: footprint.h:779
bool IsFilled() const
Definition: eda_shape.h:90
KIID m_link
Definition: footprint.h:780
FP_TEXT & Reference()
Definition: footprint.h:503
a pad used as heat sink, usually in SMD footprints
int m_localSolderMaskMargin
Definition: footprint.h:771
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:72
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: footprint.cpp:2016
EDA_RECT m_cachedBoundingBox
Definition: footprint.h:758
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:746
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:1415
const COLLECTORS_GUIDE * GetGuide() const
Definition: collectors.h:339
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:516
FP_ZONES m_fp_zones
Definition: footprint.h:737
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:1352
SHAPE_POLY_SET m_poly_courtyard_front
Definition: footprint.h:789
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:764
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:191
PAD * GetPad(const wxPoint &aPosition, LSET aLayerMask=LSET::AllLayersMask())
Get a pad at aPosition on aLayerMask in the footprint.
Definition: footprint.cpp:1095
#define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY
void SetOrientation(double aNewAngle)
Definition: footprint.cpp:1681
void Move(const wxPoint &aMoveVector) override
Move this object.
Definition: footprint.cpp:1459
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1491
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:215
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:1075
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:1191
int GetLocalClearance() const
Definition: footprint.h:213
void SetLocalClearance(int aClearance)
Definition: footprint.h:214
int m_thermalGap
Definition: footprint.h:769
const wxString & GetReference() const
Definition: footprint.h:466
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:1725
DRAWINGS & GraphicalItems()
Definition: footprint.h:172
void MoveAnchorPosition(const wxPoint &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:1608
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:741
void SetValue(const wxString &aValue)
Definition: footprint.h:496
void Rotate(const wxPoint &aRotCentre, double aAngle) override
Rotate this object.
Definition: footprint.cpp:1466
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:81
const wxString & GetKeywords() const
Definition: footprint.h:204
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:234
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:477
int GetHeight() const
Definition: eda_rect.h:119
void SetPos0(const wxPoint &aPos)
Definition: fp_text.h:165
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:153
int m_boundingBoxCacheTimeStamp
Definition: footprint.h:759
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:777
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:281
FP_GROUPS & Groups()
Definition: footprint.h:178
show footprints references (when texts are visible)
Definition: layer_ids.h:218
double GetOrientationDegrees() const
Definition: footprint.h:192
int m_thermalWidth
Definition: footprint.h:768
wxString m_keywords
Definition: footprint.h:776
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:770
virtual wxString GetClass() const =0
Return the class name.
int GetAttributes() const
Definition: footprint.h:239
bool IsType(FRAME_T aType) const
a fiducial (usually a smd) for the full board
int m_rot180Cost
Definition: footprint.h:782
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
int m_textExcludedBBoxCacheTimeStamp
Definition: footprint.h:763
wxPoint GetPosition() const override
Definition: pad.h:178
wxString GetClass() const override
Return the class name.
Definition: footprint.h:605
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:2286
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:744
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
void SetKeywords(const wxString &aKeywords)
Definition: footprint.h:205
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:1149
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:762
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:227
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:313
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
DRAWINGS m_drawings
Definition: footprint.h:735
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:1325
void SetFPIDAsString(const wxString &aFPID)
Definition: footprint.h:199
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:1299
a pad with a castellated through hole
void CacheTriangulation(bool aPartition=true)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
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:355
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:156
std::map< wxString, wxString > m_properties
Definition: footprint.h:785
#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:1433
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:1016
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
SHAPE_T GetShape() const
Definition: eda_shape.h:101
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:224
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:786
#define FP_is_PLACED
In autoplace: footprint automatically placed.
Definition: footprint.h:292
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:1562
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:738
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1293
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:136
#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:411
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:775
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:143
bool HitTestAccurate(const wxPoint &aPosition, int aAccuracy=0) const
Test if a point is inside the bounding polygon of the footprint.
Definition: footprint.cpp:1023
int GetThermalGap() const
Definition: footprint.h:237
std::list< FP_3DMODEL > m_3D_Drawings
Definition: footprint.h:784
A specialization of ZONE for use in footprints.
Definition: zone.h:947
PADS m_pads
Definition: footprint.h:736
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:1444
int m_hullCacheTimeStamp
Definition: footprint.h:765
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:745
virtual BOARD_ITEM * Duplicate() const
Create a copy of this BOARD_ITEM.
Definition: board_item.cpp:144
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
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:225