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 <dick@softplc.com>
6  * Copyright (C) 2015 Wayne Stambaugh <stambaughw@gmail.com>
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 <kicad_string.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  newGroup->AddItem( ptrMap[ member ] );
172  }
173 
174  // Copy auxiliary data: 3D_Drawings info
175  m_3D_Drawings = aFootprint.m_3D_Drawings;
176 
177  m_doc = aFootprint.m_doc;
178  m_keywords = aFootprint.m_keywords;
179  m_properties = aFootprint.m_properties;
180 
181  m_arflag = 0;
182 
184  new wxArrayString( *aFootprint.m_initial_comments ) : nullptr;
185 }
186 
187 
189  BOARD_ITEM_CONTAINER( aFootprint )
190 {
191  *this = std::move( aFootprint );
192 }
193 
194 
196 {
197  // Clean up the owned elements
198  delete m_reference;
199  delete m_value;
200  delete m_initial_comments;
201 
202  for( PAD* p : m_pads )
203  delete p;
204 
205  m_pads.clear();
206 
207  for( FP_ZONE* zone : m_fp_zones )
208  delete zone;
209 
210  m_fp_zones.clear();
211 
212  for( PCB_GROUP* group : m_fp_groups )
213  delete group;
214 
215  m_fp_groups.clear();
216 
217  for( BOARD_ITEM* d : m_drawings )
218  delete d;
219 
220  m_drawings.clear();
221 }
222 
223 
225 {
226  BOARD_ITEM::operator=( aOther );
227 
228  m_pos = aOther.m_pos;
229  m_fpid = aOther.m_fpid;
230  m_attributes = aOther.m_attributes;
231  m_fpStatus = aOther.m_fpStatus;
232  m_orient = aOther.m_orient;
233  m_rot90Cost = aOther.m_rot90Cost;
234  m_rot180Cost = aOther.m_rot180Cost;
235  m_lastEditTime = aOther.m_lastEditTime;
236  m_link = aOther.m_link;
237  m_path = aOther.m_path;
238 
239  m_cachedBoundingBox = aOther.m_cachedBoundingBox;
240  m_boundingBoxCacheTimeStamp = aOther.m_boundingBoxCacheTimeStamp;
241  m_cachedVisibleBBox = aOther.m_cachedVisibleBBox;
242  m_visibleBBoxCacheTimeStamp = aOther.m_visibleBBoxCacheTimeStamp;
243  m_cachedTextExcludedBBox = aOther.m_cachedTextExcludedBBox;
244  m_textExcludedBBoxCacheTimeStamp = aOther.m_textExcludedBBoxCacheTimeStamp;
245  m_cachedHull = aOther.m_cachedHull;
246  m_hullCacheTimeStamp = aOther.m_hullCacheTimeStamp;
247 
248  m_localClearance = aOther.m_localClearance;
249  m_localSolderMaskMargin = aOther.m_localSolderMaskMargin;
250  m_localSolderPasteMargin = aOther.m_localSolderPasteMargin;
251  m_localSolderPasteMarginRatio = aOther.m_localSolderPasteMarginRatio;
252  m_zoneConnection = aOther.m_zoneConnection;
253  m_thermalWidth = aOther.m_thermalWidth;
254  m_thermalGap = aOther.m_thermalGap;
255 
256  // Move reference and value
257  m_reference = aOther.m_reference;
258  m_reference->SetParent( this );
259  m_value = aOther.m_value;
260  m_value->SetParent( this );
261 
262 
263  // Move the pads
264  m_pads.clear();
265 
266  for( PAD* pad : aOther.Pads() )
267  Add( pad );
268 
269  aOther.Pads().clear();
270 
271  // Move the zones
272  m_fp_zones.clear();
273 
274  for( FP_ZONE* item : aOther.Zones() )
275  {
276  Add( item );
277 
278  // Ensure the net info is OK and especially uses the net info list
279  // living in the current board
280  // Needed when copying a fp from fp editor that has its own board
281  // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
282  item->SetNetCode( -1 );
283  }
284 
285  aOther.Zones().clear();
286 
287  // Move the drawings
288  m_drawings.clear();
289 
290  for( BOARD_ITEM* item : aOther.GraphicalItems() )
291  Add( item );
292 
293  aOther.GraphicalItems().clear();
294 
295  // Move the groups
296  m_fp_groups.clear();
297 
298  for( PCB_GROUP* group : aOther.Groups() )
299  Add( group );
300 
301  aOther.Groups().clear();
302 
303  // Copy auxiliary data: 3D_Drawings info
304  m_3D_Drawings.clear();
305  m_3D_Drawings = aOther.m_3D_Drawings;
306  m_doc = aOther.m_doc;
307  m_keywords = aOther.m_keywords;
308  m_properties = aOther.m_properties;
309 
310  m_initial_comments = aOther.m_initial_comments;
311 
312  // Clear the other item's containers since this is a move
313  aOther.Pads().clear();
314  aOther.Zones().clear();
315  aOther.GraphicalItems().clear();
316  aOther.m_value = nullptr;
317  aOther.m_reference = nullptr;
318  aOther.m_initial_comments = nullptr;
319 
320  return *this;
321 }
322 
323 
325 {
326  BOARD_ITEM::operator=( aOther );
327 
328  m_pos = aOther.m_pos;
329  m_fpid = aOther.m_fpid;
330  m_attributes = aOther.m_attributes;
331  m_fpStatus = aOther.m_fpStatus;
332  m_orient = aOther.m_orient;
333  m_rot90Cost = aOther.m_rot90Cost;
334  m_rot180Cost = aOther.m_rot180Cost;
336  m_link = aOther.m_link;
337  m_path = aOther.m_path;
338 
345  m_cachedHull = aOther.m_cachedHull;
347 
354  m_thermalGap = aOther.m_thermalGap;
355 
356  // Copy reference and value
357  *m_reference = *aOther.m_reference;
358  m_reference->SetParent( this );
359  *m_value = *aOther.m_value;
360  m_value->SetParent( this );
361 
362  std::map<BOARD_ITEM*, BOARD_ITEM*> ptrMap;
363 
364  // Copy pads
365  m_pads.clear();
366 
367  for( PAD* pad : aOther.Pads() )
368  {
369  PAD* newPad = new PAD( *pad );
370  ptrMap[ pad ] = newPad;
371  Add( newPad );
372  }
373 
374  // Copy zones
375  m_fp_zones.clear();
376 
377  for( FP_ZONE* zone : aOther.Zones() )
378  {
379  FP_ZONE* newZone = static_cast<FP_ZONE*>( zone->Clone() );
380  ptrMap[ zone ] = newZone;
381  Add( newZone );
382 
383  // Ensure the net info is OK and especially uses the net info list
384  // living in the current board
385  // Needed when copying a fp from fp editor that has its own board
386  // Must be NETINFO_LIST::ORPHANED_ITEM for a keepout that has no net.
387  newZone->SetNetCode( -1 );
388  }
389 
390  // Copy drawings
391  m_drawings.clear();
392 
393  for( BOARD_ITEM* item : aOther.GraphicalItems() )
394  {
395  BOARD_ITEM* newItem = static_cast<BOARD_ITEM*>( item->Clone() );
396  ptrMap[ item ] = newItem;
397  Add( newItem );
398  }
399 
400  // Copy groups
401  m_fp_groups.clear();
402 
403  for( PCB_GROUP* group : aOther.Groups() )
404  {
405  PCB_GROUP* newGroup = static_cast<PCB_GROUP*>( group->Clone() );
406  newGroup->GetItems().clear();
407 
408  for( BOARD_ITEM* member : group->GetItems() )
409  newGroup->AddItem( ptrMap[ member ] );
410 
411  Add( newGroup );
412  }
413 
414  // Copy auxiliary data: 3D_Drawings info
415  m_3D_Drawings.clear();
416  m_3D_Drawings = aOther.m_3D_Drawings;
417  m_doc = aOther.m_doc;
418  m_keywords = aOther.m_keywords;
419  m_properties = aOther.m_properties;
420 
422  new wxArrayString( *aOther.m_initial_comments ) : nullptr;
423 
424  return *this;
425 }
426 
427 
428 void FOOTPRINT::GetContextualTextVars( wxArrayString* aVars ) const
429 {
430  aVars->push_back( wxT( "REFERENCE" ) );
431  aVars->push_back( wxT( "VALUE" ) );
432  aVars->push_back( wxT( "LAYER" ) );
433 }
434 
435 
436 bool FOOTPRINT::ResolveTextVar( wxString* token, int aDepth ) const
437 {
438  if( token->IsSameAs( wxT( "REFERENCE" ) ) )
439  {
440  *token = m_reference->GetShownText( aDepth + 1 );
441  return true;
442  }
443  else if( token->IsSameAs( wxT( "VALUE" ) ) )
444  {
445  *token = m_value->GetShownText( aDepth + 1 );
446  return true;
447  }
448  else if( token->IsSameAs( wxT( "LAYER" ) ) )
449  {
450  *token = GetLayerName();
451  return true;
452  }
453  else if( m_properties.count( *token ) )
454  {
455  *token = m_properties.at( *token );
456  return true;
457  }
458 
459  return false;
460 }
461 
462 
464 {
465  // Force the ORPHANED dummy net info for all pads.
466  // ORPHANED dummy net does not depend on a board
467  for( PAD* pad : m_pads )
468  pad->SetNetCode( NETINFO_LIST::ORPHANED );
469 }
470 
471 
472 void FOOTPRINT::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
473 {
474  switch( aBoardItem->Type() )
475  {
476  case PCB_FP_TEXT_T:
477  // Only user text can be added this way.
478  assert( static_cast<FP_TEXT*>( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS );
480 
481  case PCB_FP_SHAPE_T:
482  if( aMode == ADD_MODE::APPEND )
483  m_drawings.push_back( aBoardItem );
484  else
485  m_drawings.push_front( aBoardItem );
486  break;
487 
488  case PCB_PAD_T:
489  if( aMode == ADD_MODE::APPEND )
490  m_pads.push_back( static_cast<PAD*>( aBoardItem ) );
491  else
492  m_pads.push_front( static_cast<PAD*>( aBoardItem ) );
493  break;
494 
495  case PCB_FP_ZONE_T:
496  if( aMode == ADD_MODE::APPEND )
497  m_fp_zones.push_back( static_cast<FP_ZONE*>( aBoardItem ) );
498  else
499  m_fp_zones.insert( m_fp_zones.begin(), static_cast<FP_ZONE*>( aBoardItem ) );
500  break;
501 
502  case PCB_GROUP_T:
503  if( aMode == ADD_MODE::APPEND )
504  m_fp_groups.push_back( static_cast<PCB_GROUP*>( aBoardItem ) );
505  else
506  m_fp_groups.insert( m_fp_groups.begin(), static_cast<PCB_GROUP*>( aBoardItem ) );
507  break;
508 
509  default:
510  {
511  wxString msg;
512  msg.Printf( wxT( "FOOTPRINT::Add() needs work: BOARD_ITEM type (%d) not handled" ),
513  aBoardItem->Type() );
514  wxFAIL_MSG( msg );
515 
516  return;
517  }
518  }
519 
520  aBoardItem->ClearEditFlags();
521  aBoardItem->SetParent( this );
522 }
523 
524 
525 void FOOTPRINT::Remove( BOARD_ITEM* aBoardItem, REMOVE_MODE aMode )
526 {
527  switch( aBoardItem->Type() )
528  {
529  case PCB_FP_TEXT_T:
530  // Only user text can be removed this way.
531  wxCHECK_RET(
532  static_cast<FP_TEXT*>( aBoardItem )->GetType() == FP_TEXT::TEXT_is_DIVERS,
533  "Please report this bug: Invalid remove operation on required text" );
535 
536  case PCB_FP_SHAPE_T:
537  for( auto it = m_drawings.begin(); it != m_drawings.end(); ++it )
538  {
539  if( *it == aBoardItem )
540  {
541  m_drawings.erase( it );
542  break;
543  }
544  }
545 
546  break;
547 
548  case PCB_PAD_T:
549  for( auto it = m_pads.begin(); it != m_pads.end(); ++it )
550  {
551  if( *it == static_cast<PAD*>( aBoardItem ) )
552  {
553  m_pads.erase( it );
554  break;
555  }
556  }
557 
558  break;
559 
560  case PCB_FP_ZONE_T:
561  for( auto it = m_fp_zones.begin(); it != m_fp_zones.end(); ++it )
562  {
563  if( *it == static_cast<FP_ZONE*>( aBoardItem ) )
564  {
565  m_fp_zones.erase( it );
566  break;
567  }
568  }
569 
570  break;
571 
572  case PCB_GROUP_T:
573  for( auto it = m_fp_groups.begin(); it != m_fp_groups.end(); ++it )
574  {
575  if( *it == static_cast<PCB_GROUP*>( aBoardItem ) )
576  {
577  m_fp_groups.erase( it );
578  break;
579  }
580  }
581 
582  break;
583 
584  default:
585  {
586  wxString msg;
587  msg.Printf( wxT( "FOOTPRINT::Remove() needs work: BOARD_ITEM type (%d) not handled" ),
588  aBoardItem->Type() );
589  wxFAIL_MSG( msg );
590  }
591  }
592 
593  aBoardItem->SetFlags( STRUCT_DELETED );
594 
595  PCB_GROUP* parentGroup = aBoardItem->GetParentGroup();
596 
597  if( parentGroup && !( parentGroup->GetFlags() & STRUCT_DELETED ) )
598  parentGroup->RemoveItem( aBoardItem );
599 }
600 
601 
602 double FOOTPRINT::GetArea( int aPadding ) const
603 {
604  EDA_RECT bbox = GetBoundingBox( false, false );
605 
606  double w = std::abs( static_cast<double>( bbox.GetWidth() ) ) + aPadding;
607  double h = std::abs( static_cast<double>( bbox.GetHeight() ) ) + aPadding;
608  return w * h;
609 }
610 
611 
613 {
614  EDA_RECT area;
615 
616  // We want the bounding box of the footprint pads at rot 0, not flipped
617  // Create such a image:
618  FOOTPRINT dummy( *this );
619 
620  dummy.SetPosition( wxPoint( 0, 0 ) );
621 
622  if( dummy.IsFlipped() )
623  dummy.Flip( wxPoint( 0, 0 ) , false );
624 
625  if( dummy.GetOrientation() )
626  dummy.SetOrientation( 0 );
627 
628  for( PAD* pad : dummy.Pads() )
629  area.Merge( pad->GetBoundingBox() );
630 
631  return area;
632 }
633 
634 
636 {
637  return GetBoundingBox( true, true );
638 }
639 
640 
641 const EDA_RECT FOOTPRINT::GetBoundingBox( bool aIncludeText, bool aIncludeInvisibleText ) const
642 {
643  BOARD* board = GetBoard();
644 
645  if( board )
646  {
647  if( aIncludeText && aIncludeInvisibleText )
648  {
649  if( m_boundingBoxCacheTimeStamp >= board->GetTimeStamp() )
650  return m_cachedBoundingBox;
651  }
652  else if( aIncludeText )
653  {
654  if( m_visibleBBoxCacheTimeStamp >= board->GetTimeStamp() )
655  return m_cachedVisibleBBox;
656  }
657  else
658  {
661  }
662  }
663 
664  EDA_RECT area;
665 
666  area.SetOrigin( m_pos );
667  area.SetEnd( m_pos );
668  area.Inflate( Millimeter2iu( 0.25 ) ); // Give a min size to the area
669 
670  for( BOARD_ITEM* item : m_drawings )
671  {
672  if( item->Type() == PCB_FP_SHAPE_T )
673  area.Merge( item->GetBoundingBox() );
674  }
675 
676  for( PAD* pad : m_pads )
677  area.Merge( pad->GetBoundingBox() );
678 
679  for( FP_ZONE* zone : m_fp_zones )
680  area.Merge( zone->GetBoundingBox() );
681 
682  bool noDrawItems = ( m_drawings.empty() && m_pads.empty() && m_fp_zones.empty() );
683 
684  // Groups do not contribute to the rect, only their members
685  if( aIncludeText || noDrawItems )
686  {
687  for( BOARD_ITEM* item : m_drawings )
688  {
689  if( item->Type() == PCB_FP_TEXT_T )
690  area.Merge( item->GetBoundingBox() );
691  }
692 
693  // This can be further optimized when aIncludeInvisibleText is true, but currently
694  // leaving this as is until it's determined there is a noticeable speed hit.
695  bool valueLayerIsVisible = true;
696  bool refLayerIsVisible = true;
697 
698  if( board )
699  {
700  // The first "&&" conditional handles the user turning layers off as well as layers
701  // not being present in the current PCB stackup. Values, references, and all
702  // footprint text can also be turned off via the GAL meta-layers, so the 2nd and
703  // 3rd "&&" conditionals handle that.
704  valueLayerIsVisible = board->IsLayerVisible( m_value->GetLayer() )
706  && board->IsElementVisible( LAYER_MOD_TEXT_FR );
707 
708  refLayerIsVisible = board->IsLayerVisible( m_reference->GetLayer() )
710  && board->IsElementVisible( LAYER_MOD_TEXT_FR );
711  }
712 
713 
714  if( ( m_value->IsVisible() && valueLayerIsVisible )
715  || aIncludeInvisibleText || noDrawItems )
716  area.Merge( m_value->GetBoundingBox() );
717 
718  if( ( m_reference->IsVisible() && refLayerIsVisible )
719  || aIncludeInvisibleText || noDrawItems )
720  area.Merge( m_reference->GetBoundingBox() );
721  }
722 
723  if( board )
724  {
725  if( ( aIncludeText && aIncludeInvisibleText ) || noDrawItems )
726  {
728  m_cachedBoundingBox = area;
729  }
730  else if( aIncludeText )
731  {
733  m_cachedVisibleBBox = area;
734  }
735  else
736  {
739  }
740  }
741 
742  return area;
743 }
744 
745 
747 {
748  BOARD* board = GetBoard();
749 
750  if( board )
751  {
752  if( m_hullCacheTimeStamp >= board->GetTimeStamp() )
753  return m_cachedHull;
754  }
755 
756  SHAPE_POLY_SET rawPolys;
757  SHAPE_POLY_SET hull;
758 
759  for( BOARD_ITEM* item : m_drawings )
760  {
761  if( item->Type() == PCB_FP_SHAPE_T )
762  {
763  item->TransformShapeWithClearanceToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
764  ERROR_OUTSIDE );
765  }
766 
767  // We intentionally exclude footprint text from the bounding hull.
768  }
769 
770  for( PAD* pad : m_pads )
771  {
772  pad->TransformShapeWithClearanceToPolygon( rawPolys, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
773  ERROR_OUTSIDE );
774  }
775 
776  for( FP_ZONE* zone : m_fp_zones )
777  {
778  for( PCB_LAYER_ID layer : zone->GetLayerSet().Seq() )
779  {
780  SHAPE_POLY_SET layerPoly = zone->GetFilledPolysList( layer );
781 
782  for( int ii = 0; ii < layerPoly.OutlineCount(); ii++ )
783  {
784  const SHAPE_LINE_CHAIN& poly = layerPoly.COutline( ii );
785  rawPolys.AddOutline( poly );
786  }
787  }
788  }
789 
790  // If there are some graphic items, build the actual hull.
791  // However if no items, create a minimal polygon (can happen if a footprint
792  // is created with no item: it contains only 2 texts.
793  if( rawPolys.OutlineCount() == 0 )
794  {
795  // generate a small dummy rectangular outline around the anchor
796  const int halfsize = Millimeter2iu( 1.0 );
797 
798  rawPolys.NewOutline();
799 
800  // add a square:
801  rawPolys.Append( GetPosition().x - halfsize, GetPosition().y - halfsize );
802  rawPolys.Append( GetPosition().x + halfsize, GetPosition().y - halfsize );
803  rawPolys.Append( GetPosition().x + halfsize, GetPosition().y + halfsize );
804  rawPolys.Append( GetPosition().x - halfsize, GetPosition().y + halfsize );
805  }
806 
807  std::vector<wxPoint> convex_hull;
808  BuildConvexHull( convex_hull, rawPolys );
809 
812 
813  for( const wxPoint& pt : convex_hull )
814  m_cachedHull.Append( pt );
815 
816  if( board )
818 
819  return m_cachedHull;
820 }
821 
822 
823 void FOOTPRINT::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
824 {
825  wxString msg, msg2;
826 
827  aList.emplace_back( m_reference->GetShownText(), m_value->GetShownText() );
828 
829  if( aFrame->IsType( FRAME_FOOTPRINT_VIEWER )
831  || aFrame->IsType( FRAME_FOOTPRINT_EDITOR ) )
832  {
833  wxDateTime date( static_cast<time_t>( m_lastEditTime ) );
834 
835  // Date format: see http://www.cplusplus.com/reference/ctime/strftime
836  if( m_lastEditTime && date.IsValid() )
837  msg = date.Format( wxT( "%b %d, %Y" ) ); // Abbreviated_month_name Day, Year
838  else
839  msg = _( "Unknown" );
840 
841  aList.emplace_back( _( "Last Change" ), msg );
842  }
843  else if( aFrame->IsType( FRAME_PCB_EDITOR ) )
844  {
845  aList.emplace_back( _( "Board Side" ), IsFlipped() ? _( "Back (Flipped)" ) : _( "Front" ) );
846  }
847 
848  auto addToken = []( wxString* aStr, const wxString& aAttr )
849  {
850  if( !aStr->IsEmpty() )
851  *aStr += wxT( ", " );
852 
853  *aStr += aAttr;
854  };
855 
856  wxString status;
857  wxString attrs;
858 
859  if( IsLocked() )
860  addToken( &status, _( "Locked" ) );
861 
862  if( m_fpStatus & FP_is_PLACED )
863  addToken( &status, _( "autoplaced" ) );
864 
866  addToken( &attrs, _( "not in schematic" ) );
867 
869  addToken( &attrs, _( "exclude from pos files" ) );
870 
872  addToken( &attrs, _( "exclude from BOM" ) );
873 
874  aList.emplace_back( _( "Status: " ) + status, _( "Attributes:" ) + wxS( " " ) + attrs );
875 
876  aList.emplace_back( _( "Rotation" ), wxString::Format( "%.4g", GetOrientationDegrees() ) );
877 
878  msg.Printf( _( "Footprint: %s" ), m_fpid.Format().c_str() );
879  msg2.Printf( _( "3D-Shape: %s" ), m_3D_Drawings.empty() ? _( "<none>" )
880  : m_3D_Drawings.front().m_Filename );
881  aList.emplace_back( msg, msg2 );
882 
883  msg.Printf( _( "Doc: %s" ), m_doc );
884  msg2.Printf( _( "Keywords: %s" ), m_keywords );
885  aList.emplace_back( msg, msg2 );
886 }
887 
888 
889 bool FOOTPRINT::IsOnLayer( PCB_LAYER_ID aLayer ) const
890 {
891  // If we have any pads, fall back on normal checking
892  if( !m_pads.empty() )
893  return m_layer == aLayer;
894 
895  // No pads? Check if this entire footprint exists on the given layer
896  for( FP_ZONE* zone : m_fp_zones )
897  {
898  if( !zone->IsOnLayer( aLayer ) )
899  return false;
900  }
901 
902  for( BOARD_ITEM* item : m_drawings )
903  {
904  if( !item->IsOnLayer( aLayer ) )
905  return false;
906  }
907 
908  return true;
909 }
910 
911 
912 bool FOOTPRINT::HitTest( const wxPoint& aPosition, int aAccuracy ) const
913 {
914  EDA_RECT rect = GetBoundingBox( false, false );
915  return rect.Inflate( aAccuracy ).Contains( aPosition );
916 }
917 
918 
919 bool FOOTPRINT::HitTestAccurate( const wxPoint& aPosition, int aAccuracy ) const
920 {
921  return GetBoundingHull().Collide( aPosition, aAccuracy );
922 }
923 
924 
925 bool FOOTPRINT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
926 {
927  EDA_RECT arect = aRect;
928  arect.Inflate( aAccuracy );
929 
930  if( aContained )
931  {
932  return arect.Contains( GetBoundingBox( false, false ) );
933  }
934  else
935  {
936  // If the rect does not intersect the bounding box, skip any tests
937  if( !aRect.Intersects( GetBoundingBox( false, false ) ) )
938  return false;
939 
940  // The empty footprint dummy rectangle intersects the selection area.
941  if( m_pads.empty() && m_fp_zones.empty() && m_drawings.empty() )
942  return GetBoundingBox( true, false ).Intersects( arect );
943 
944  // Determine if any elements in the FOOTPRINT intersect the rect
945  for( PAD* pad : m_pads )
946  {
947  if( pad->HitTest( arect, false, 0 ) )
948  return true;
949  }
950 
951  for( FP_ZONE* zone : m_fp_zones )
952  {
953  if( zone->HitTest( arect, false, 0 ) )
954  return true;
955  }
956 
957  for( BOARD_ITEM* item : m_drawings )
958  {
959  if( item->Type() != PCB_FP_TEXT_T && item->HitTest( arect, false, 0 ) )
960  return true;
961  }
962 
963  // Groups are not hit-tested; only their members
964 
965  // No items were hit
966  return false;
967  }
968 }
969 
970 
971 PAD* FOOTPRINT::FindPadByName( const wxString& aPadName ) const
972 {
973  for( PAD* pad : m_pads )
974  {
975  if( pad->GetName() == aPadName )
976  return pad;
977  }
978 
979  return nullptr;
980 }
981 
982 
983 PAD* FOOTPRINT::GetPad( const wxPoint& aPosition, LSET aLayerMask )
984 {
985  for( PAD* pad : m_pads )
986  {
987  // ... and on the correct layer.
988  if( !( pad->GetLayerSet() & aLayerMask ).any() )
989  continue;
990 
991  if( pad->HitTest( aPosition ) )
992  return pad;
993  }
994 
995  return nullptr;
996 }
997 
998 
1000 {
1001  PAD* topLeftPad = m_pads.front();
1002 
1003  for( PAD* p : m_pads )
1004  {
1005  wxPoint pnt = p->GetPosition(); // GetPosition() returns the center of the pad
1006 
1007  if( ( pnt.x < topLeftPad->GetPosition().x ) ||
1008  ( topLeftPad->GetPosition().x == pnt.x && pnt.y < topLeftPad->GetPosition().y ) )
1009  {
1010  topLeftPad = p;
1011  }
1012  }
1013 
1014  return topLeftPad;
1015 }
1016 
1017 
1018 unsigned FOOTPRINT::GetPadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1019 {
1020  if( aIncludeNPTH )
1021  return m_pads.size();
1022 
1023  unsigned cnt = 0;
1024 
1025  for( PAD* pad : m_pads )
1026  {
1027  if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1028  continue;
1029 
1030  cnt++;
1031  }
1032 
1033  return cnt;
1034 }
1035 
1036 
1037 unsigned FOOTPRINT::GetUniquePadCount( INCLUDE_NPTH_T aIncludeNPTH ) const
1038 {
1039  std::set<wxString> usedNames;
1040 
1041  // Create a set of used pad numbers
1042  for( PAD* pad : m_pads )
1043  {
1044  // Skip pads not on copper layers (used to build complex
1045  // solder paste shapes for instance)
1046  if( ( pad->GetLayerSet() & LSET::AllCuMask() ).none() )
1047  continue;
1048 
1049  // Skip pads with no name, because they are usually "mechanical"
1050  // pads, not "electrical" pads
1051  if( pad->GetName().IsEmpty() )
1052  continue;
1053 
1054  if( !aIncludeNPTH )
1055  {
1056  // skip NPTH
1057  if( pad->GetAttribute() == PAD_ATTRIB::NPTH )
1058  {
1059  continue;
1060  }
1061  }
1062 
1063  usedNames.insert( pad->GetName() );
1064  }
1065 
1066  return usedNames.size();
1067 }
1068 
1069 
1071 {
1072  if( nullptr == a3DModel )
1073  return;
1074 
1075  if( !a3DModel->m_Filename.empty() )
1076  m_3D_Drawings.push_back( *a3DModel );
1077 }
1078 
1079 
1080 // see footprint.h
1081 SEARCH_RESULT FOOTPRINT::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
1082 {
1083  KICAD_T stype;
1085  const KICAD_T* p = scanTypes;
1086  bool done = false;
1087 
1088 #if 0 && defined(DEBUG)
1089  std::cout << GetClass().mb_str() << ' ';
1090 #endif
1091 
1092  while( !done )
1093  {
1094  stype = *p;
1095 
1096  switch( stype )
1097  {
1098  case PCB_FOOTPRINT_T:
1099  result = inspector( this, testData ); // inspect me
1100  ++p;
1101  break;
1102 
1103  case PCB_PAD_T:
1104  result = IterateForward<PAD*>( m_pads, inspector, testData, p );
1105  ++p;
1106  break;
1107 
1108  case PCB_FP_ZONE_T:
1109  result = IterateForward<FP_ZONE*>( m_fp_zones, inspector, testData, p );
1110  ++p;
1111  break;
1112 
1113  case PCB_FP_TEXT_T:
1114  result = inspector( m_reference, testData );
1115 
1116  if( result == SEARCH_RESULT::QUIT )
1117  break;
1118 
1119  result = inspector( m_value, testData );
1120 
1121  if( result == SEARCH_RESULT::QUIT )
1122  break;
1123 
1124  // Intentionally fall through since m_Drawings can hold PCB_FP_SHAPE_T also
1126 
1127  case PCB_FP_SHAPE_T:
1128  result = IterateForward<BOARD_ITEM*>( m_drawings, inspector, testData, p );
1129 
1130  // skip over any types handled in the above call.
1131  for( ; ; )
1132  {
1133  switch( stype = *++p )
1134  {
1135  case PCB_FP_TEXT_T:
1136  case PCB_FP_SHAPE_T:
1137  continue;
1138 
1139  default:
1140  ;
1141  }
1142 
1143  break;
1144  }
1145 
1146  break;
1147 
1148  case PCB_GROUP_T:
1149  result = IterateForward<PCB_GROUP*>( m_fp_groups, inspector, testData, p );
1150  ++p;
1151  break;
1152 
1153  default:
1154  done = true;
1155  break;
1156  }
1157 
1158  if( result == SEARCH_RESULT::QUIT )
1159  break;
1160  }
1161 
1162  return result;
1163 }
1164 
1165 
1166 wxString FOOTPRINT::GetSelectMenuText( EDA_UNITS aUnits ) const
1167 {
1168  wxString reference = GetReference();
1169 
1170  if( reference.IsEmpty() )
1171  reference = _( "<no reference designator>" );
1172 
1173  return wxString::Format( _( "Footprint %s" ), reference );
1174 }
1175 
1176 
1178 {
1179  return BITMAPS::module;
1180 }
1181 
1182 
1184 {
1185  return new FOOTPRINT( *this );
1186 }
1187 
1188 
1189 void FOOTPRINT::RunOnChildren( const std::function<void ( BOARD_ITEM*)>& aFunction ) const
1190 {
1191  try
1192  {
1193  for( PAD* pad : m_pads )
1194  aFunction( static_cast<BOARD_ITEM*>( pad ) );
1195 
1196  for( FP_ZONE* zone : m_fp_zones )
1197  aFunction( static_cast<FP_ZONE*>( zone ) );
1198 
1199  for( PCB_GROUP* group : m_fp_groups )
1200  aFunction( static_cast<PCB_GROUP*>( group ) );
1201 
1202  for( BOARD_ITEM* drawing : m_drawings )
1203  aFunction( static_cast<BOARD_ITEM*>( drawing ) );
1204 
1205  aFunction( static_cast<BOARD_ITEM*>( m_reference ) );
1206  aFunction( static_cast<BOARD_ITEM*>( m_value ) );
1207  }
1208  catch( std::bad_function_call& )
1209  {
1210  wxFAIL_MSG( "Error running FOOTPRINT::RunOnChildren" );
1211  }
1212 }
1213 
1214 
1215 void FOOTPRINT::GetAllDrawingLayers( int aLayers[], int& aCount, bool aIncludePads ) const
1216 {
1217  std::unordered_set<int> layers;
1218 
1219  for( BOARD_ITEM* item : m_drawings )
1220  layers.insert( static_cast<int>( item->GetLayer() ) );
1221 
1222  if( aIncludePads )
1223  {
1224  for( PAD* pad : m_pads )
1225  {
1226  int pad_layers[KIGFX::VIEW::VIEW_MAX_LAYERS], pad_layers_count;
1227  pad->ViewGetLayers( pad_layers, pad_layers_count );
1228 
1229  for( int i = 0; i < pad_layers_count; i++ )
1230  layers.insert( pad_layers[i] );
1231  }
1232  }
1233 
1234  aCount = layers.size();
1235  int i = 0;
1236 
1237  for( int layer : layers )
1238  aLayers[i++] = layer;
1239 }
1240 
1241 
1242 void FOOTPRINT::ViewGetLayers( int aLayers[], int& aCount ) const
1243 {
1244  aCount = 2;
1245  aLayers[0] = LAYER_ANCHOR;
1246 
1247  switch( m_layer )
1248  {
1249  default:
1250  wxASSERT_MSG( false, "Illegal layer" ); // do you really have footprints placed on
1251  // other layers?
1253 
1254  case F_Cu:
1255  aLayers[1] = LAYER_MOD_FR;
1256  break;
1257 
1258  case B_Cu:
1259  aLayers[1] = LAYER_MOD_BK;
1260  break;
1261  }
1262 
1263  // If there are no pads, and only drawings on a silkscreen layer, then report the silkscreen
1264  // layer as well so that the component can be edited with the silkscreen layer
1265  bool f_silk = false, b_silk = false, non_silk = false;
1266 
1267  for( BOARD_ITEM* item : m_drawings )
1268  {
1269  if( item->GetLayer() == F_SilkS )
1270  f_silk = true;
1271  else if( item->GetLayer() == B_SilkS )
1272  b_silk = true;
1273  else
1274  non_silk = true;
1275  }
1276 
1277  if( ( f_silk || b_silk ) && !non_silk && m_pads.empty() )
1278  {
1279  if( f_silk )
1280  aLayers[ aCount++ ] = F_SilkS;
1281 
1282  if( b_silk )
1283  aLayers[ aCount++ ] = B_SilkS;
1284  }
1285 }
1286 
1287 
1288 double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1289 {
1290  int layer = ( m_layer == F_Cu ) ? LAYER_MOD_FR :
1292 
1293  // Currently this is only pertinent for the anchor layer; everything else is drawn from the
1294  // children.
1295  // The "good" value is experimentally chosen.
1296  #define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY 1.5
1297 
1298  if( aView->IsLayerVisible( layer ) )
1300 
1301  return std::numeric_limits<double>::max();
1302 }
1303 
1304 
1306 {
1307  EDA_RECT area = GetBoundingBox( true, true );
1308 
1309  // Add the Clearance shape size: (shape around the pads when the clearance is shown. Not
1310  // optimized, but the draw cost is small (perhaps smaller than optimization).
1311  BOARD* board = GetBoard();
1312 
1313  if( board )
1314  {
1315  int biggest_clearance = board->GetDesignSettings().GetBiggestClearanceValue();
1316  area.Inflate( biggest_clearance );
1317  }
1318 
1319  return area;
1320 }
1321 
1322 
1323 bool FOOTPRINT::IsLibNameValid( const wxString & aName )
1324 {
1325  const wxChar * invalids = StringLibNameInvalidChars( false );
1326 
1327  if( aName.find_first_of( invalids ) != std::string::npos )
1328  return false;
1329 
1330  return true;
1331 }
1332 
1333 
1334 const wxChar* FOOTPRINT::StringLibNameInvalidChars( bool aUserReadable )
1335 {
1336  // This list of characters is also duplicated in validators.cpp and
1337  // lib_id.cpp
1338  // TODO: Unify forbidden character lists
1339  static const wxChar invalidChars[] = wxT("%$<>\t\n\r\"\\/:");
1340  static const wxChar invalidCharsReadable[] = wxT("% $ < > 'tab' 'return' 'line feed' \\ \" / :");
1341 
1342  if( aUserReadable )
1343  return invalidCharsReadable;
1344  else
1345  return invalidChars;
1346 }
1347 
1348 
1349 void FOOTPRINT::Move( const wxPoint& aMoveVector )
1350 {
1351  wxPoint newpos = m_pos + aMoveVector;
1352  SetPosition( newpos );
1353 }
1354 
1355 
1356 void FOOTPRINT::Rotate( const wxPoint& aRotCentre, double aAngle )
1357 {
1358  double orientation = GetOrientation();
1359  double newOrientation = orientation + aAngle;
1360  wxPoint newpos = m_pos;
1361  RotatePoint( &newpos, aRotCentre, aAngle );
1362  SetPosition( newpos );
1363  SetOrientation( newOrientation );
1364 
1365  m_reference->KeepUpright( orientation, newOrientation );
1366  m_value->KeepUpright( orientation, newOrientation );
1367 
1368  for( BOARD_ITEM* item : m_drawings )
1369  {
1370  if( item->Type() == PCB_FP_TEXT_T )
1371  static_cast<FP_TEXT*>( item )->KeepUpright( orientation, newOrientation );
1372  }
1373 
1378 }
1379 
1380 
1381 void FOOTPRINT::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
1382 {
1383  // Move footprint to its final position:
1384  wxPoint finalPos = m_pos;
1385 
1386  // Now Flip the footprint.
1387  // Flipping a footprint is a specific transform: it is not mirrored like a text.
1388  // We have to change the side, and ensure the footprint rotation is modified according to the
1389  // transform, because this parameter is used in pick and place files, and when updating the
1390  // footprint from library.
1391  // When flipped around the X axis (Y coordinates changed) orientation is negated
1392  // When flipped around the Y axis (X coordinates changed) orientation is 180 - old orient.
1393  // Because it is specific to a footprint, we flip around the X axis, and after rotate 180 deg
1394 
1395  MIRROR( finalPos.y, aCentre.y );
1396 
1397  SetPosition( finalPos );
1398 
1399  // Flip layer
1400  SetLayer( FlipLayer( GetLayer() ) );
1401 
1402  // Reverse mirror orientation.
1403  m_orient = -m_orient;
1404 
1406 
1407  // Mirror pads to other side of board.
1408  for( PAD* pad : m_pads )
1409  pad->Flip( m_pos, false );
1410 
1411  // Mirror zones to other side of board.
1412  for( ZONE* zone : m_fp_zones )
1413  zone->Flip( m_pos, false );
1414 
1415  // Mirror reference and value.
1416  m_reference->Flip( m_pos, false );
1417  m_value->Flip( m_pos, false );
1418 
1419  // Reverse mirror footprint graphics and texts.
1420  for( BOARD_ITEM* item : m_drawings )
1421  {
1422  switch( item->Type() )
1423  {
1424  case PCB_FP_SHAPE_T:
1425  static_cast<FP_SHAPE*>( item )->Flip( m_pos, false );
1426  break;
1427 
1428  case PCB_FP_TEXT_T:
1429  static_cast<FP_TEXT*>( item )->Flip( m_pos, false );
1430  break;
1431 
1432  default:
1433  wxMessageBox( wxT( "FOOTPRINT::Flip() error: Unknown Draw Type" ) );
1434  break;
1435  }
1436  }
1437 
1438  // Now rotate 180 deg if required
1439  if( aFlipLeftRight )
1440  Rotate( aCentre, 1800.0 );
1441 
1445 
1446  m_cachedHull.Mirror( aFlipLeftRight, !aFlipLeftRight, m_pos );
1447 
1449 }
1450 
1451 
1452 void FOOTPRINT::SetPosition( const wxPoint& aPos )
1453 {
1454  wxPoint delta = aPos - m_pos;
1455 
1456  m_pos += delta;
1457 
1458  m_reference->EDA_TEXT::Offset( delta );
1459  m_value->EDA_TEXT::Offset( delta );
1460 
1461  for( PAD* pad : m_pads )
1462  pad->SetPosition( pad->GetPosition() + delta );
1463 
1464  for( ZONE* zone : m_fp_zones )
1465  zone->Move( delta );
1466 
1467  for( BOARD_ITEM* item : m_drawings )
1468  {
1469  switch( item->Type() )
1470  {
1471  case PCB_FP_SHAPE_T:
1472  {
1473  FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1474  shape->SetDrawCoord();
1475  break;
1476  }
1477 
1478  case PCB_FP_TEXT_T:
1479  {
1480  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1481  text->EDA_TEXT::Offset( delta );
1482  break;
1483  }
1484 
1485  default:
1486  wxMessageBox( wxT( "Draw type undefined." ) );
1487  break;
1488  }
1489  }
1490 
1491  m_cachedBoundingBox.Move( delta );
1492  m_cachedVisibleBBox.Move( delta );
1493  m_cachedTextExcludedBBox.Move( delta );
1494  m_cachedHull.Move( delta );
1495 }
1496 
1497 
1498 void FOOTPRINT::MoveAnchorPosition( const wxPoint& aMoveVector )
1499 {
1500  /* Move the reference point of the footprint
1501  * the footprints elements (pads, outlines, edges .. ) are moved
1502  * but:
1503  * - the footprint position is not modified.
1504  * - the relative (local) coordinates of these items are modified
1505  * - Draw coordinates are updated
1506  */
1507 
1508 
1509  // Update (move) the relative coordinates relative to the new anchor point.
1510  wxPoint moveVector = aMoveVector;
1511  RotatePoint( &moveVector, -GetOrientation() );
1512 
1513  // Update of the reference and value.
1514  m_reference->SetPos0( m_reference->GetPos0() + moveVector );
1516  m_value->SetPos0( m_value->GetPos0() + moveVector );
1517  m_value->SetDrawCoord();
1518 
1519  // Update the pad local coordinates.
1520  for( PAD* pad : m_pads )
1521  {
1522  pad->SetPos0( pad->GetPos0() + moveVector );
1523  pad->SetDrawCoord();
1524  }
1525 
1526  // Update the draw element coordinates.
1527  for( BOARD_ITEM* item : GraphicalItems() )
1528  {
1529  switch( item->Type() )
1530  {
1531  case PCB_FP_SHAPE_T:
1532  {
1533  FP_SHAPE* shape = static_cast<FP_SHAPE*>( item );
1534  shape->Move( moveVector );
1535  }
1536  break;
1537 
1538  case PCB_FP_TEXT_T:
1539  {
1540  FP_TEXT* text = static_cast<FP_TEXT*>( item );
1541  text->SetPos0( text->GetPos0() + moveVector );
1542  text->SetDrawCoord();
1543  }
1544  break;
1545 
1546  default:
1547  break;
1548  }
1549  }
1550 
1551  // Update the keepout zones
1552  for( ZONE* zone : Zones() )
1553  {
1554  zone->Move( moveVector );
1555  }
1556 
1557  // Update the 3D models
1558  for( FP_3DMODEL& model : Models() )
1559  {
1560  model.m_Offset.x += Iu2Millimeter( moveVector.x );
1561  model.m_Offset.y -= Iu2Millimeter( moveVector.y );
1562  }
1563 
1564  m_cachedBoundingBox.Move( moveVector );
1565  m_cachedVisibleBBox.Move( moveVector );
1566  m_cachedTextExcludedBBox.Move( moveVector );
1567  m_cachedHull.Move( moveVector );
1568 }
1569 
1570 
1571 void FOOTPRINT::SetOrientation( double aNewAngle )
1572 {
1573  double angleChange = aNewAngle - m_orient; // change in rotation
1574 
1575  NORMALIZE_ANGLE_180( aNewAngle );
1576 
1577  m_orient = aNewAngle;
1578 
1579  for( PAD* pad : m_pads )
1580  {
1581  pad->SetOrientation( pad->GetOrientation() + angleChange );
1582  pad->SetDrawCoord();
1583  }
1584 
1585  for( ZONE* zone : m_fp_zones )
1586  {
1587  zone->Rotate( GetPosition(), angleChange );
1588  }
1589 
1590  // Update of the reference and value.
1592  m_value->SetDrawCoord();
1593 
1594  // Displace contours and text of the footprint.
1595  for( BOARD_ITEM* item : m_drawings )
1596  {
1597  if( item->Type() == PCB_FP_SHAPE_T )
1598  {
1599  static_cast<FP_SHAPE*>( item )->SetDrawCoord();
1600  }
1601  else if( item->Type() == PCB_FP_TEXT_T )
1602  {
1603  static_cast<FP_TEXT*>( item )->SetDrawCoord();
1604  }
1605  }
1606 
1610 
1611  m_cachedHull.Rotate( -DECIDEG2RAD( angleChange ), GetPosition() );
1612 }
1613 
1614 
1616 {
1617  FOOTPRINT* dupe = (FOOTPRINT*) Clone();
1618  const_cast<KIID&>( dupe->m_Uuid ) = KIID();
1619 
1620  dupe->RunOnChildren( [&]( BOARD_ITEM* child )
1621  {
1622  const_cast<KIID&>( child->m_Uuid ) = KIID();
1623  });
1624 
1625  return static_cast<BOARD_ITEM*>( dupe );
1626 }
1627 
1628 
1629 BOARD_ITEM* FOOTPRINT::DuplicateItem( const BOARD_ITEM* aItem, bool aAddToFootprint )
1630 {
1631  BOARD_ITEM* new_item = nullptr;
1632  FP_ZONE* new_zone = nullptr;
1633 
1634  switch( aItem->Type() )
1635  {
1636  case PCB_PAD_T:
1637  {
1638  PAD* new_pad = new PAD( *static_cast<const PAD*>( aItem ) );
1639  const_cast<KIID&>( new_pad->m_Uuid ) = KIID();
1640 
1641  if( aAddToFootprint )
1642  m_pads.push_back( new_pad );
1643 
1644  new_item = new_pad;
1645  break;
1646  }
1647 
1648  case PCB_FP_ZONE_T:
1649  {
1650  new_zone = new FP_ZONE( *static_cast<const FP_ZONE*>( aItem ) );
1651  const_cast<KIID&>( new_zone->m_Uuid ) = KIID();
1652 
1653  if( aAddToFootprint )
1654  m_fp_zones.push_back( new_zone );
1655 
1656  new_item = new_zone;
1657  break;
1658  }
1659 
1660  case PCB_FP_TEXT_T:
1661  {
1662  FP_TEXT* new_text = new FP_TEXT( *static_cast<const FP_TEXT*>( aItem ) );
1663  const_cast<KIID&>( new_text->m_Uuid ) = KIID();
1664 
1665  if( new_text->GetType() == FP_TEXT::TEXT_is_REFERENCE )
1666  {
1667  new_text->SetText( wxT( "${REFERENCE}" ) );
1668  new_text->SetType( FP_TEXT::TEXT_is_DIVERS );
1669  }
1670  else if( new_text->GetType() == FP_TEXT::TEXT_is_VALUE )
1671  {
1672  new_text->SetText( wxT( "${VALUE}" ) );
1673  new_text->SetType( FP_TEXT::TEXT_is_DIVERS );
1674  }
1675 
1676  if( aAddToFootprint )
1677  Add( new_text );
1678 
1679  new_item = new_text;
1680 
1681  break;
1682  }
1683 
1684  case PCB_FP_SHAPE_T:
1685  {
1686  FP_SHAPE* new_shape = new FP_SHAPE( *static_cast<const FP_SHAPE*>( aItem ) );
1687  const_cast<KIID&>( new_shape->m_Uuid ) = KIID();
1688 
1689  if( aAddToFootprint )
1690  Add( new_shape );
1691 
1692  new_item = new_shape;
1693  break;
1694  }
1695 
1696  case PCB_GROUP_T:
1697  new_item = static_cast<const PCB_GROUP*>( aItem )->DeepDuplicate();
1698  break;
1699 
1700  case PCB_FOOTPRINT_T:
1701  // Ignore the footprint itself
1702  break;
1703 
1704  default:
1705  // Un-handled item for duplication
1706  wxFAIL_MSG( "Duplication not supported for items of class " + aItem->GetClass() );
1707  break;
1708  }
1709 
1710  return new_item;
1711 }
1712 
1713 
1714 wxString FOOTPRINT::GetNextPadName( const wxString& aLastPadName ) const
1715 {
1716  std::set<wxString> usedNames;
1717 
1718  // Create a set of used pad numbers
1719  for( PAD* pad : m_pads )
1720  usedNames.insert( pad->GetName() );
1721 
1722  // Pad names aren't technically reference designators, but the formatting is close enough
1723  // for these to give us what we need.
1724  wxString prefix = UTIL::GetRefDesPrefix( aLastPadName );
1725  int num = GetTrailingInt( aLastPadName );
1726 
1727  while( usedNames.count( wxString::Format( "%s%d", prefix, num ) ) )
1728  num++;
1729 
1730  return wxString::Format( "%s%d", prefix, num );
1731 }
1732 
1733 
1735 {
1736  const wxString& refdes = GetReference();
1737 
1738  SetReference( wxString::Format( wxT( "%s%i" ),
1739  UTIL::GetRefDesPrefix( refdes ),
1740  GetTrailingInt( refdes ) + aDelta ) );
1741 }
1742 
1743 
1744 // Calculate the area of aPolySet, after fracturation, because
1745 // polygons with no hole are expected.
1746 static double polygonArea( SHAPE_POLY_SET& aPolySet )
1747 {
1748  double area = 0.0;
1749 
1750  for( int ii = 0; ii < aPolySet.OutlineCount(); ii++ )
1751  {
1752  SHAPE_LINE_CHAIN& outline = aPolySet.Outline( ii );
1753  // Ensure the curr outline is closed, to calculate area
1754  outline.SetClosed( true );
1755 
1756  area += outline.Area();
1757  }
1758 
1759  return area;
1760 }
1761 
1762 
1763 double FOOTPRINT::GetCoverageArea( const BOARD_ITEM* aItem, const GENERAL_COLLECTOR& aCollector )
1764 {
1765  int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
1766  SHAPE_POLY_SET poly;
1767 
1768  if( aItem->Type() == PCB_MARKER_T )
1769  {
1770  const PCB_MARKER* marker = static_cast<const PCB_MARKER*>( aItem );
1771  SHAPE_LINE_CHAIN markerShape;
1772 
1773  marker->ShapeToPolygon( markerShape );
1774  return markerShape.Area();
1775  }
1776  else if( aItem->Type() == PCB_GROUP_T )
1777  {
1778  double combinedArea = 0.0;
1779 
1780  for( BOARD_ITEM* member : static_cast<const PCB_GROUP*>( aItem )->GetItems() )
1781  combinedArea += GetCoverageArea( member, aCollector );
1782 
1783  return combinedArea;
1784  }
1785  if( aItem->Type() == PCB_FOOTPRINT_T )
1786  {
1787  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( aItem );
1788 
1789  poly = footprint->GetBoundingHull();
1790  }
1791  else if( aItem->Type() == PCB_FP_TEXT_T )
1792  {
1793  const FP_TEXT* text = static_cast<const FP_TEXT*>( aItem );
1794 
1795  text->TransformTextShapeWithClearanceToPolygon( poly, UNDEFINED_LAYER, textMargin,
1796  ARC_LOW_DEF, ERROR_OUTSIDE );
1797  }
1798  else if( aItem->Type() == PCB_SHAPE_T )
1799  {
1800  // Approximate "linear" shapes with just their width squared, as we don't want to consider
1801  // a linear shape as being much bigger than another for purposes of selection filtering
1802  // just because it happens to be really long.
1803 
1804  const PCB_SHAPE* shape = static_cast<const PCB_SHAPE*>( aItem );
1805 
1806  switch( shape->GetShape() )
1807  {
1809  case PCB_SHAPE_TYPE::ARC:
1810  case PCB_SHAPE_TYPE::CURVE:
1811  return shape->GetWidth() * shape->GetWidth();
1812 
1813  case PCB_SHAPE_TYPE::RECT:
1816  {
1817  if( !shape->IsFilled() )
1818  return shape->GetWidth() * shape->GetWidth();
1819 
1821  }
1822 
1823  default:
1825  ARC_LOW_DEF, ERROR_OUTSIDE );
1826  }
1827  }
1828  else if( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_ARC_T )
1829  {
1830  double width = static_cast<const PCB_TRACK*>( aItem )->GetWidth();
1831  return width * width;
1832  }
1833  else
1834  {
1836  ARC_LOW_DEF, ERROR_OUTSIDE );
1837  }
1838 
1839  poly.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1840  poly.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1841  return polygonArea( poly );
1842 }
1843 
1844 
1845 double FOOTPRINT::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
1846 {
1847  int textMargin = KiROUND( 5 * aCollector.GetGuide()->OnePixelInIU() );
1848 
1849  SHAPE_POLY_SET footprintRegion( GetBoundingHull() );
1850  SHAPE_POLY_SET coveredRegion;
1851 
1852  TransformPadsWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, 0, ARC_LOW_DEF,
1853  ERROR_OUTSIDE );
1854 
1855  TransformFPShapesWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, textMargin,
1856  ARC_LOW_DEF, ERROR_OUTSIDE,
1857  true, /* include text */
1858  false /* include shapes */ );
1859 
1860  for( int i = 0; i < aCollector.GetCount(); ++i )
1861  {
1862  const BOARD_ITEM* item = aCollector[i];
1863 
1864  switch( item->Type() )
1865  {
1866  case PCB_FP_TEXT_T:
1867  case PCB_FP_SHAPE_T:
1868  if( item->GetParent() != this )
1869  {
1870  item->TransformShapeWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, 0,
1871  ARC_LOW_DEF, ERROR_OUTSIDE );
1872  }
1873  break;
1874 
1875  case PCB_TEXT_T:
1876  case PCB_SHAPE_T:
1877  case PCB_TRACE_T:
1878  case PCB_ARC_T:
1879  case PCB_VIA_T:
1880  item->TransformShapeWithClearanceToPolygon( coveredRegion, UNDEFINED_LAYER, 0,
1881  ARC_LOW_DEF, ERROR_OUTSIDE );
1882  break;
1883 
1884  case PCB_FOOTPRINT_T:
1885  if( item != this )
1886  {
1887  const FOOTPRINT* footprint = static_cast<const FOOTPRINT*>( item );
1888  coveredRegion.AddOutline( footprint->GetBoundingHull().Outline( 0 ) );
1889  }
1890  break;
1891 
1892  default:
1893  break;
1894  }
1895  }
1896 
1897  SHAPE_POLY_SET uncoveredRegion;
1898 
1899  try
1900  {
1901  uncoveredRegion.BooleanSubtract( footprintRegion, coveredRegion,
1903  uncoveredRegion.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1904  uncoveredRegion.Fracture( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1905  }
1906  catch( ClipperLib::clipperException& )
1907  {
1908  // better to be conservative (this will result in the disambiguate dialog)
1909  return 1.0;
1910  }
1911 
1912  double footprintRegionArea = polygonArea( footprintRegion );
1913  double uncoveredRegionArea = polygonArea( uncoveredRegion );
1914  double coveredArea = footprintRegionArea - uncoveredRegionArea;
1915  double ratio = ( coveredArea / footprintRegionArea );
1916 
1917  return std::min( ratio, 1.0 );
1918 }
1919 
1920 
1921 std::shared_ptr<SHAPE> FOOTPRINT::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
1922 {
1923  std::shared_ptr<SHAPE_COMPOUND> shape = std::make_shared<SHAPE_COMPOUND>();
1924 
1925  // There are several possible interpretations here:
1926  // 1) the bounding box (without or without invisible items)
1927  // 2) just the pads and "edges" (ie: non-text graphic items)
1928  // 3) the courtyard
1929 
1930  // We'll go with (2) for now....
1931 
1932  for( PAD* pad : Pads() )
1933  shape->AddShape( pad->GetEffectiveShape( aLayer )->Clone() );
1934 
1935  for( BOARD_ITEM* item : GraphicalItems() )
1936  {
1937  if( item->Type() == PCB_FP_SHAPE_T )
1938  shape->AddShape( item->GetEffectiveShape( aLayer )->Clone() );
1939  }
1940 
1941  return shape;
1942 }
1943 
1944 
1946 {
1950 
1951  // Build the courtyard area from graphic items on the courtyard.
1952  // Only PCB_FP_SHAPE_T have meaning, graphic texts are ignored.
1953  // Collect items:
1954  std::vector<PCB_SHAPE*> list_front;
1955  std::vector<PCB_SHAPE*> list_back;
1956 
1957  for( BOARD_ITEM* item : GraphicalItems() )
1958  {
1959  if( item->GetLayer() == B_CrtYd && item->Type() == PCB_FP_SHAPE_T )
1960  list_back.push_back( static_cast<PCB_SHAPE*>( item ) );
1961 
1962  if( item->GetLayer() == F_CrtYd && item->Type() == PCB_FP_SHAPE_T )
1963  list_front.push_back( static_cast<PCB_SHAPE*>( item ) );
1964  }
1965 
1966  if( !list_front.size() && !list_back.size() )
1967  return;
1968 
1969  int errorMax = Millimeter2iu( 0.02 ); // max error for polygonization
1970  int chainingEpsilon = Millimeter2iu( 0.02 ); // max dist from one endPt to next startPt
1971 
1972  if( ConvertOutlineToPolygon( list_front, m_poly_courtyard_front, errorMax, chainingEpsilon,
1973  aErrorHandler ) )
1974  {
1975  // Touching courtyards, or courtyards -at- the clearance distance are legal.
1977 
1979  }
1980  else
1981  {
1983  }
1984 
1985  if( ConvertOutlineToPolygon( list_back, m_poly_courtyard_back, errorMax, chainingEpsilon,
1986  aErrorHandler ) )
1987  {
1988  // Touching courtyards, or courtyards -at- the clearance distance are legal.
1990 
1992  }
1993  else
1994  {
1996  }
1997 }
1998 
1999 
2001 {
2002  assert( aImage->Type() == PCB_FOOTPRINT_T );
2003 
2004  std::swap( *((FOOTPRINT*) this), *((FOOTPRINT*) aImage) );
2005 }
2006 
2007 
2009 {
2010  for( PAD* pad : Pads() )
2011  {
2012  if( pad->GetAttribute() != PAD_ATTRIB::SMD )
2013  return true;
2014  }
2015 
2016  return false;
2017 }
2018 
2019 
2021  const BOARD_ITEM* aSecond ) const
2022 {
2023  if( aFirst->Type() != aSecond->Type() )
2024  return aFirst->Type() < aSecond->Type();
2025 
2026  if( aFirst->GetLayer() != aSecond->GetLayer() )
2027  return aFirst->GetLayer() < aSecond->GetLayer();
2028 
2029  if( aFirst->Type() == PCB_FP_SHAPE_T )
2030  {
2031  const FP_SHAPE* dwgA = static_cast<const FP_SHAPE*>( aFirst );
2032  const FP_SHAPE* dwgB = static_cast<const FP_SHAPE*>( aSecond );
2033 
2034  if( dwgA->GetShape() != dwgB->GetShape() )
2035  return dwgA->GetShape() < dwgB->GetShape();
2036  }
2037 
2038  if( aFirst->m_Uuid != aSecond->m_Uuid ) // shopuld be always the case foer valid boards
2039  return aFirst->m_Uuid < aSecond->m_Uuid;
2040 
2041  return aFirst < aSecond;
2042 }
2043 
2044 
2045 bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) const
2046 {
2047  if( aFirst->GetName() != aSecond->GetName() )
2048  return StrNumCmp( aFirst->GetName(), aSecond->GetName() ) < 0;
2049 
2050  if( aFirst->m_Uuid != aSecond->m_Uuid ) // shopuld be always the case foer valid boards
2051  return aFirst->m_Uuid < aSecond->m_Uuid;
2052 
2053  return aFirst < aSecond;
2054 }
2055 
2056 
2057 static struct FOOTPRINT_DESC
2058 {
2060  {
2062 
2063  if( layerEnum.Choices().GetCount() == 0 )
2064  {
2065  layerEnum.Undefined( UNDEFINED_LAYER );
2066 
2067  for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
2068  layerEnum.Map( *seq, LSET::Name( *seq ) );
2069  }
2070 
2071  wxPGChoices fpLayers; // footprints might be placed only on F.Cu & B.Cu
2072  fpLayers.Add( LSET::Name( F_Cu ), F_Cu );
2073  fpLayers.Add( LSET::Name( B_Cu ), B_Cu );
2074 
2081 
2082  auto layer = new PROPERTY_ENUM<FOOTPRINT, PCB_LAYER_ID, BOARD_ITEM>( _HKI( "Layer" ),
2084  layer->SetChoices( fpLayers );
2085  propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Layer" ), layer );
2086 
2087  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Reference" ),
2089  propMgr.AddProperty( new PROPERTY<FOOTPRINT, wxString>( _HKI( "Value" ),
2091  propMgr.AddProperty( new PROPERTY<FOOTPRINT, double>( _HKI( "Orientation" ),
2094  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Clearance Override" ),
2097  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Solderpaste Margin Override" ),
2100  propMgr.AddProperty( new PROPERTY<FOOTPRINT,
2101  double>( _HKI( "Solderpaste Margin Ratio Override" ),
2104  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Thermal Relief Width" ),
2108  propMgr.AddProperty( new PROPERTY<FOOTPRINT, int>( _HKI( "Thermal Relief Gap" ),
2112  // TODO zone connection, FPID?
2113  }
2114 } _FOOTPRINT_DESC;
void SetReference(const wxString &aReference)
Definition: footprint.h:430
void BuildPolyCourtyards(OUTLINE_ERROR_HANDLER *aErrorHandler=nullptr)
Build complex polygons of the courtyard areas from graphic items on the courtyard layers.
Definition: footprint.cpp:1945
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
Display value expressed in degrees.
Definition: property.h:54
PCB_GROUP * GetParentGroup() const
Definition: board_item.h:91
int m_localSolderPasteMargin
Definition: footprint.h:714
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:1629
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:1763
bool IsLocked() const override
Definition: footprint.h:277
bool AddItem(BOARD_ITEM *aItem)
Add item to group.
Definition: pcb_group.cpp:38
double GetArea(int aPadding=0) const
Definition: footprint.cpp:602
void ClearAllNets()
Clear (i.e.
Definition: footprint.cpp:463
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: footprint.cpp:1288
bool IsFilled() const
Definition: pcb_shape.h:75
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:702
#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:746
int OutlineCount() const
Return the number of vertices in a given outline/hole.
int StrNumCmp(const wxString &aString1, const wxString &aString2, bool aIgnoreCase)
Compare two strings with alphanumerical content.
Definition: string.cpp:507
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
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:1166
#define MALFORMED_B_COURTYARD
std::list< FP_3DMODEL > & Models()
Definition: footprint.h:173
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:823
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:889
const wxString & GetValue() const
Definition: footprint.h:443
unsigned GetPadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of pads.
Definition: footprint.cpp:1018
ZONE_CONNECTION m_zoneConnection
Definition: footprint.h:709
double m_localSolderPasteMarginRatio
Definition: footprint.h:715
SHAPE_POLY_SET m_poly_courtyard_back
Definition: footprint.h:732
virtual void SetLayer(PCB_LAYER_ID aLayer)
Set the layer this item is on.
Definition: board_item.h:192
This file is part of the common library.
virtual void SetPosition(const wxPoint &aPos)
Definition: eda_item.h:253
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:108
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:50
virtual double OnePixelInIU() const =0
anchor of items having an anchor point (texts, footprints)
ENUM_MAP & Undefined(T aValue)
Definition: property.h:523
PCB_SHAPE_TYPE GetShape() const
Definition: pcb_shape.h:110
#define FP_PADS_are_LOCKED
Definition: footprint.h:274
bool IsVisible() const
Definition: eda_text.h:193
double m_orient
Definition: footprint.h:682
bool ResolveTextVar(wxString *token, int aDepth=0) const
Resolve any references to system tokens supported by the component.
Definition: footprint.cpp:436
#define MALFORMED_F_COURTYARD
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:521
int GetWidth() const
Definition: pcb_shape.h:97
Smd pad, appears on the solder paste layer (default)
timestamp_t m_lastEditTime
Definition: footprint.h:720
Collection of utility functions for component reference designators (refdes)
int GetWidth() const
Definition: eda_rect.h:109
show footprints on back
void Remove(BOARD_ITEM *aItem, REMOVE_MODE aMode=REMOVE_MODE::NORMAL) override
Removes an item from the container.
Definition: footprint.cpp:525
static ENUM_MAP< T > & Instance()
Definition: property.h:510
double GetOrientation() const
Definition: footprint.h:181
void SetFlags(EDA_ITEM_FLAGS aMask)
Definition: eda_item.h:153
class PCB_TEXT, text on a layer
Definition: typeinfo.h:91
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:1845
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
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:121
show footprints values (when texts are visible)
void SetLocalSolderPasteMarginRatio(double aRatio)
Definition: footprint.h:215
functions to convert a shape built with DRAWSEGMENTS to a polygon.
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:180
FP_TEXT * m_reference
Definition: footprint.h:684
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
int m_visibleBBoxCacheTimeStamp
Definition: footprint.h:703
INCLUDE_NPTH_T
Definition: footprint.h:55
void NORMALIZE_ANGLE_180(T &Angle)
Definition: trigo.h:385
wxPGChoices & Choices()
Definition: property.h:559
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:228
void SetThermalGap(int aGap)
Definition: footprint.h:223
The base class for create windows for drawing purpose.
void SetType(TEXT_TYPE aType)
Definition: fp_text.h:140
std::unordered_set< BOARD_ITEM * > & GetItems()
Definition: pcb_group.h:68
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:588
#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:1177
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:94
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:2045
virtual void SetParent(EDA_ITEM *aParent)
Definition: eda_item.h:116
static constexpr int VIEW_MAX_LAYERS
maximum number of layers that may be shown
Definition: view.h:701
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:95
int m_rot90Cost
Definition: footprint.h:723
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:159
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:2000
void Add3DModel(FP_3DMODEL *a3DModel)
Add a3DModel definition to the end of the 3D model list.
Definition: footprint.cpp:1070
void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:40
const char * c_str() const
Definition: utf8.h:102
FP_TEXT * m_value
Definition: footprint.h:685
PAD * GetTopLeftPad()
Definition: footprint.cpp:999
void SetThermalWidth(int aWidth)
Definition: footprint.h:220
int m_arflag
Definition: footprint.h:721
polygon (not yet used for tracks, but could be in microwave apps)
KIID m_link
Definition: footprint.h:722
show footprints on front
int m_localSolderMaskMargin
Definition: footprint.h:713
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:70
EDA_RECT m_cachedBoundingBox
Definition: footprint.h:700
int GetCount() const
Return the number of objects in the list.
Definition: collector.h:87
FP_ZONES & Zones()
Definition: footprint.h:165
Definition: kiid.h:44
void SetClosed(bool aClosed)
Function SetClosed()
int m_fpStatus
Definition: footprint.h:688
like PAD_PTH, but not plated
PCB_LAYER_ID
A quick note on layer IDs:
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:1305
const COLLECTORS_GUIDE * GetGuide() const
Definition: collectors.h:339
LSET is a set of PCB_LAYER_IDs.
FP_ZONES m_fp_zones
Definition: footprint.h:679
virtual void SetText(const wxString &aText)
Definition: eda_text.cpp:114
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:1242
SHAPE_POLY_SET m_poly_courtyard_front
Definition: footprint.h:731
void IncrementReference(int aDelta)
Bump the current reference by aDelta.
Definition: footprint.cpp:1734
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:706
SHAPE_LINE_CHAIN & Outline(int aIndex)
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:983
#define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY
void SetOrientation(double aNewAngle)
Definition: footprint.cpp:1571
void Move(const wxPoint &aMoveVector) override
Move this object.
Definition: footprint.cpp:1349
segment with non rounded ends
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: footprint.cpp:1381
virtual BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:50
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
const wxString & GetName() const
Definition: pad.h:130
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:1081
int GetLocalClearance() const
Definition: footprint.h:200
void SetLocalClearance(int aClearance)
Definition: footprint.h:201
int m_thermalGap
Definition: footprint.h:711
const wxString & GetReference() const
Definition: footprint.h:421
#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:154
BOARD_ITEM * Duplicate() const override
Create a copy of this BOARD_ITEM.
Definition: footprint.cpp:1615
DRAWINGS & GraphicalItems()
Definition: footprint.h:162
void MoveAnchorPosition(const wxPoint &aMoveVector)
Move the reference point of the footprint.
Definition: footprint.cpp:1498
static LSET AllLayersMask()
Definition: lset.cpp:787
bool RemoveItem(BOARD_ITEM *aItem)
Remove item from group.
Definition: pcb_group.cpp:50
void Simplify(POLYGON_MODE aFastMode)
Handle a list of polygons defining a copper zone.
Definition: zone.h:57
wxPoint m_pos
Definition: footprint.h:683
PAD * FindPadByName(const wxString &aPadName) const
Return a PAD with a matching name.
Definition: footprint.cpp:971
void SetValue(const wxString &aValue)
Definition: footprint.h:451
void Rotate(const wxPoint &aRotCentre, double aAngle) override
Rotate this object.
Definition: footprint.cpp:1356
void SetDrawCoord()
Set draw coordinates (absolute values ) from relative coordinates.
Definition: fp_shape.cpp:82
int NewOutline()
Creates a new hole in a given outline.
Acute angles are chamfered.
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,...
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.
int GetThermalWidth() const
Definition: footprint.h:221
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition: eda_item.cpp:179
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
int GetHeight() const
Definition: eda_rect.h:110
UTF8 Format() const
Definition: lib_id.cpp:233
void SetPos0(const wxPoint &aPos)
Definition: fp_text.h:165
int m_boundingBoxCacheTimeStamp
Definition: footprint.h:701
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:369
EDA_ITEM_FLAGS GetFlags() const
Definition: eda_item.h:155
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:719
const KIID m_Uuid
Definition: eda_item.h:475
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Test whether a given element category is visible.
Definition: board.cpp:531
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:97
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:2020
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:428
bool IsFlipped() const
Definition: footprint.h:261
FP_GROUPS & Groups()
Definition: footprint.h:168
double GetOrientationDegrees() const
Definition: footprint.h:182
int m_thermalWidth
Definition: footprint.h:710
wxString m_keywords
Definition: footprint.h:718
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:471
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:712
virtual wxString GetClass() const =0
Return the class name.
bool IsType(FRAME_T aType) const
int m_rot180Cost
Definition: footprint.h:724
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:32
int m_textExcludedBBoxCacheTimeStamp
Definition: footprint.h:705
wxPoint GetPosition() const override
Definition: pad.h:174
wxString GetClass() const override
Return the class name.
Definition: footprint.h:553
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...
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:190
SHAPE_LINE_CHAIN.
LIB_ID m_fpid
Definition: footprint.h:686
int GetTimeStamp()
Definition: board.h:214
wxString GetNextPadName(const wxString &aLastPadName) const
Return the next available pad name in the footprint.
Definition: footprint.cpp:1714
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:635
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:235
usual segment : line with rounded ends
FOOTPRINT & operator=(const FOOTPRINT &aOther)
Definition: footprint.cpp:324
unsigned GetUniquePadCount(INCLUDE_NPTH_T aIncludeNPTH=INCLUDE_NPTH_T(INCLUDE_NPTH)) const
Return the number of unique non-blank pads.
Definition: footprint.cpp:1037
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:70
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:100
EDA_RECT m_cachedTextExcludedBBox
Definition: footprint.h:704
const std::function< void(const wxString &msg, BOARD_ITEM *itemA, BOARD_ITEM *itemB, const wxPoint &pt)> OUTLINE_ERROR_HANDLER
wxPoint GetPosition() const override
Definition: footprint.h:177
int GetTrailingInt(const wxString &aStr)
Gets the trailing int, if any, from a string.
Definition: string.cpp:804
double GetLocalSolderPasteMarginRatio() const
Definition: footprint.h:214
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:355
wxString GetRefDesPrefix(const wxString &aRefDes)
Get the (non-numeric) prefix from a refdes - e.g.
DRAWINGS m_drawings
Definition: footprint.h:677
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:1215
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:62
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:1189
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:289
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:133
std::map< wxString, wxString > m_properties
Definition: footprint.h:727
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:1323
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Test if aPosition is contained within or on the bounding box of an item.
Definition: footprint.cpp:912
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
Abstract interface for BOARD_ITEMs capable of storing other items inside.
int GetLocalSolderPasteMargin() const
Definition: footprint.h:211
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
Removes an item from the container.
Definition: footprint.cpp:472
wxArrayString * m_initial_comments
Definition: footprint.h:728
#define FP_is_PLACED
In autoplace: footprint automatically placed.
Definition: footprint.h:272
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:1452
void ClearEditFlags()
Definition: eda_item.h:172
SEARCH_RESULT
Definition: eda_item.h:41
Arcs (with rounded ends)
FP_GROUPS m_fp_groups
Definition: footprint.h:680
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: footprint.cpp:1183
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:166
#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:414
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:64
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:2008
wxString m_doc
Definition: footprint.h:717
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:171
bool HitTestAccurate(const wxPoint &aPosition, int aAccuracy=0) const
Test if a point is inside the bounding polygon of the footprint.
Definition: footprint.cpp:919
int GetThermalGap() const
Definition: footprint.h:224
std::list< FP_3DMODEL > m_3D_Drawings
Definition: footprint.h:726
A specialization of ZONE for use in footprints.
Definition: zone.h:943
PADS m_pads
Definition: footprint.h:678
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:1334
show footprints references (when texts are visible)
int m_hullCacheTimeStamp
Definition: footprint.h:707
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:687
EDA_RECT GetFpPadsLocalBbox() const
Return the bounding box containing pads when the footprint is on the front side, orientation 0,...
Definition: footprint.cpp:612
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:113
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:404
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:1921
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:1746
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:212