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