KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
multichannel_tool.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24
25#include <board_commit.h>
26#include <tools/pcb_actions.h>
27
30
31#include "multichannel_tool.h"
32
33#include <pcbexpr_evaluator.h>
34
35#include <zone.h>
38#include <pcb_group.h>
42#include <optional>
43#include <algorithm>
45#include <pcb_track.h>
46#include <tool/tool_manager.h>
48#include <random>
49#include <core/profile.h>
50#include <wx/log.h>
51#include <pgm_base.h>
52
53
54#define MULTICHANNEL_EXTRA_DEBUG
55
56static const wxString traceMultichannelTool = wxT( "MULTICHANNEL_TOOL" );
57
58
60{
61}
62
63
65{
66
67}
68
69
71{
74}
75
76
78 std::set<FOOTPRINT*>& aComponents )
79{
81 PCBEXPR_UCODE ucode;
82 PCBEXPR_CONTEXT ctx, preflightCtx;
83
84 auto reportError = [&]( const wxString& aMessage, int aOffset )
85 {
86 wxLogTrace( traceMultichannelTool, wxT( "ERROR: %s"), aMessage );
87 };
88
89 ctx.SetErrorCallback( reportError );
90 preflightCtx.SetErrorCallback( reportError );
91 compiler.SetErrorCallback( reportError );
92 //compiler.SetDebugReporter( m_reporter );
93
94 wxLogTrace( traceMultichannelTool, wxT( "rule area '%s'"), aRuleArea->GetZoneName() );
95
96 wxString ruleText;
97
98 switch( aRuleArea->GetRuleAreaPlacementSourceType() )
99 {
100 case RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME:
101 {
102 ruleText = wxT( "A.memberOfSheetOrChildren('" ) + aRuleArea->GetRuleAreaPlacementSource()
103 + wxT( "')" );
104 break;
105 }
106 case RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS:
107 ruleText = wxT( "A.hasComponentClass('" ) + aRuleArea->GetRuleAreaPlacementSource()
108 + wxT( "')" );
109 break;
110 }
111
112 auto ok = compiler.Compile( ruleText, &ucode, &preflightCtx );
113
114 if( !ok )
115 {
116 return false;
117 }
118
119 for( FOOTPRINT* fp : board()->Footprints() )
120 {
121 ctx.SetItems( fp, fp );
122 auto val = ucode.Run( &ctx );
123 if( val->AsDouble() != 0.0 )
124 {
125 wxLogTrace( traceMultichannelTool, wxT( " - %s [sheet %s]" ), fp->GetReference(),
126 fp->GetSheetname() );
127
128 aComponents.insert( fp );
129 }
130 }
131
132 return true;
133}
134
135
136bool MULTICHANNEL_TOOL::findOtherItemsInRuleArea( ZONE* aRuleArea, std::set<BOARD_ITEM*>& aItems )
137{
138 std::vector<BOARD_ITEM*> result;
139
141 PCBEXPR_UCODE ucode;
142 PCBEXPR_CONTEXT ctx, preflightCtx;
143
144 auto reportError = [&]( const wxString& aMessage, int aOffset )
145 {
146 wxLogTrace( traceMultichannelTool, wxT( "ERROR: %s"), aMessage );
147 };
148
149 ctx.SetErrorCallback( reportError );
150 preflightCtx.SetErrorCallback( reportError );
151 compiler.SetErrorCallback( reportError );
152
153 bool restoreBlankName = false;
154
155 if( aRuleArea->GetZoneName().IsEmpty() )
156 {
157 restoreBlankName = true;
158 aRuleArea->SetZoneName( aRuleArea->m_Uuid.AsString() );
159 }
160
161 wxString ruleText = wxString::Format( wxT( "A.enclosedByArea('%s')" ), aRuleArea->GetZoneName() );
162
163 if( !compiler.Compile( ruleText, &ucode, &preflightCtx ) )
164 {
165 if( restoreBlankName )
166 aRuleArea->SetZoneName( wxEmptyString );
167
168 return false;
169 }
170
171 auto testAndAdd =
172 [&]( BOARD_ITEM* aItem )
173 {
174 ctx.SetItems( aItem, aItem );
175 auto val = ucode.Run( &ctx );
176
177 if( val->AsDouble() != 0.0 )
178 aItems.insert( aItem );
179 };
180
181 for( ZONE* zone : board()->Zones() )
182 {
183 if( zone == aRuleArea )
184 continue;
185
186 testAndAdd( zone );
187 }
188
189 for( BOARD_ITEM* drawing : board()->Drawings() )
190 testAndAdd( drawing );
191
192 for( PCB_GROUP* group : board()->Groups() )
193 {
194 // A group is cloned in its entirety if *all* children are contained
195 bool addGroup = true;
196
197 group->RunOnChildren(
198 [&]( BOARD_ITEM* aItem )
199 {
200 if( aItem->IsType( { PCB_ZONE_T, PCB_SHAPE_T, PCB_DIMENSION_T } ) )
201 {
202 ctx.SetItems( aItem, aItem );
203 auto val = ucode.Run( &ctx );
204
205 if( val->AsDouble() == 0.0 )
206 addGroup = false;
207 }
208 },
209 RECURSE_MODE::RECURSE );
210
211 if( addGroup )
212 aItems.insert( group );
213 }
214
215 if( restoreBlankName )
216 aRuleArea->SetZoneName( wxEmptyString );
217
218 return true;
219}
220
221
222std::set<FOOTPRINT*> MULTICHANNEL_TOOL::queryComponentsInSheet( wxString aSheetName ) const
223{
224 std::set<FOOTPRINT*> rv;
225 if( aSheetName.EndsWith( wxT( "/" ) ) )
226 aSheetName.RemoveLast();
227
228 for( auto& fp : board()->Footprints() )
229 {
230 auto sn = fp->GetSheetname();
231 if( sn.EndsWith( wxT( "/" ) ) )
232 sn.RemoveLast();
233
234 if( sn == aSheetName )
235 {
236 rv.insert( fp );
237 }
238 }
239
240 return rv;
241}
242
243
244std::set<FOOTPRINT*>
245MULTICHANNEL_TOOL::queryComponentsInComponentClass( const wxString& aComponentClassName ) const
246{
247 std::set<FOOTPRINT*> rv;
248
249 for( auto& fp : board()->Footprints() )
250 {
251 if( fp->GetComponentClass()->ContainsClassName( aComponentClassName ) )
252 rv.insert( fp );
253 }
254
255 return rv;
256}
257
258
259const SHAPE_LINE_CHAIN MULTICHANNEL_TOOL::buildRAOutline( std::set<FOOTPRINT*>& aFootprints,
260 int aMargin )
261{
262 std::vector<VECTOR2I> bbCorners;
263 bbCorners.reserve( aFootprints.size() * 4 );
264
265 for( auto fp : aFootprints )
266 {
267 const BOX2I bb = fp->GetBoundingBox( false ).GetInflated( aMargin );
268 KIGEOM::CollectBoxCorners( bb, bbCorners );
269 }
270
271 std::vector<VECTOR2I> hullVertices;
272 BuildConvexHull( hullVertices, bbCorners );
273
274 SHAPE_LINE_CHAIN hull( hullVertices );
275
276 // Make the newly computed convex hull use only 90 degree segments
277 return KIGEOM::RectifyPolygon( hull );
278}
279
280
282{
283 using PathAndName = std::pair<wxString, wxString>;
284 std::set<PathAndName> uniqueSheets;
285 std::set<wxString> uniqueComponentClasses;
286
287 m_areas.m_areas.clear();
288
289 for( const FOOTPRINT* fp : board()->Footprints() )
290 {
291 uniqueSheets.insert( PathAndName( fp->GetSheetname(), fp->GetSheetfile() ) );
292
293 const COMPONENT_CLASS* compClass = fp->GetComponentClass();
294
295 for( const COMPONENT_CLASS* singleClass : compClass->GetConstituentClasses() )
296 uniqueComponentClasses.insert( singleClass->GetName() );
297 }
298
299 for( const PathAndName& sheet : uniqueSheets )
300 {
301 RULE_AREA ent;
302
303 ent.m_sourceType = RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME;
304 ent.m_generateEnabled = false;
305 ent.m_sheetPath = sheet.first;
306 ent.m_sheetName = sheet.second;
308 m_areas.m_areas.push_back( ent );
309
310 wxLogTrace( traceMultichannelTool, wxT("found sheet '%s' @ '%s' s %d\n"),
311 ent.m_sheetName, ent.m_sheetPath, (int)m_areas.m_areas.size() );
312 }
313
314 for( const wxString& compClass : uniqueComponentClasses )
315 {
316 RULE_AREA ent;
317
318 ent.m_sourceType = RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS;
319 ent.m_generateEnabled = false;
320 ent.m_componentClass = compClass;
322 m_areas.m_areas.push_back( ent );
323
324 wxLogTrace( traceMultichannelTool, wxT( "found component class '%s' s %d\n" ),
325 ent.m_componentClass, static_cast<int>( m_areas.m_areas.size() ) );
326 }
327}
328
329
331{
332 m_areas.m_areas.clear();
333
334 for( ZONE* zone : board()->Zones() )
335 {
336 if( !zone->GetIsRuleArea() )
337 continue;
338 if( !zone->GetRuleAreaPlacementEnabled() )
339 continue;
340
341 RULE_AREA area;
342
343 area.m_existsAlready = true;
344 area.m_area = zone;
345
347
348 area.m_ruleName = zone->GetZoneName();
349 area.m_center = zone->Outline()->COutline( 0 ).Centre();
350 m_areas.m_areas.push_back( area );
351
352 wxLogTrace( traceMultichannelTool, wxT("RA '%s', %d footprints\n"), area.m_ruleName, (int) area.m_raFootprints.size() );
353 }
354
355 wxLogTrace( traceMultichannelTool, wxT("Total RAs found: %d\n"), (int) m_areas.m_areas.size() );
356}
357
358
360{
361 for( RULE_AREA& ra : m_areas.m_areas )
362 {
363 if( ra.m_ruleName == aName )
364 return &ra;
365 }
366
367 return nullptr;
368}
369
370
372{
374}
375
376
378{
379 std::vector<ZONE*> refRAs;
380
381 auto isSelectedItemAnRA = []( EDA_ITEM* aItem ) -> ZONE*
382 {
383 if( !aItem || aItem->Type() != PCB_ZONE_T )
384 return nullptr;
385
386 ZONE* zone = static_cast<ZONE*>( aItem );
387
388 if( !zone->GetIsRuleArea() )
389 return nullptr;
390
391 if( !zone->GetRuleAreaPlacementEnabled() )
392 return nullptr;
393
394 return zone;
395 };
396
397 for( EDA_ITEM* item : selection() )
398 {
399 if( auto zone = isSelectedItemAnRA( item ) )
400 {
401 refRAs.push_back(zone);
402 }
403 else if ( item->Type() == PCB_GROUP_T )
404 {
405 PCB_GROUP *group = static_cast<PCB_GROUP*>( item );
406
407 for( BOARD_ITEM* grpItem : group->GetItems() )
408 {
409 if( auto grpZone = isSelectedItemAnRA( grpItem ) )
410 {
411 refRAs.push_back( grpZone );
412 }
413 }
414 }
415 }
416
417 if( refRAs.size() != 1 )
418 {
421 this,
422 _( "Select a reference Rule Area to copy from..." ),
423 [&]( EDA_ITEM* aItem )
424 {
425 return isSelectedItemAnRA( aItem ) != nullptr;
426 }
427 } );
428
429 return 0;
430 }
431
433
434 int status = CheckRACompatibility( refRAs.front() );
435
436 if( status < 0 )
437 return status;
438
439 if( m_areas.m_areas.size() <= 1 )
440 {
441 frame()->ShowInfoBarError( _( "No Rule Areas to repeat layout to have been found." ),
442 true );
443 return 0;
444 }
445
447 int ret = dialog.ShowModal();
448
449 if( ret != wxID_OK )
450 return 0;
451
452 return RepeatLayout( aEvent, refRAs.front() );
453}
454
455
457{
458 m_areas.m_refRA = nullptr;
459
460 for( RULE_AREA& ra : m_areas.m_areas )
461 {
462 if( ra.m_area == aRefZone )
463 {
464 m_areas.m_refRA = &ra;
465 break;
466 }
467 }
468
469 if( !m_areas.m_refRA )
470 return -1;
471
472 m_areas.m_compatMap.clear();
473
474 for( RULE_AREA& ra : m_areas.m_areas )
475 {
476 if( ra.m_area == m_areas.m_refRA->m_area )
477 continue;
478
480
482 }
483
484 return 0;
485}
486
487
488int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
489{
490 int totalCopied = 0;
491
492 BOARD_COMMIT commit( GetManager(), true );
493
494 for( auto& targetArea : m_areas.m_compatMap )
495 {
496 if( !targetArea.second.m_doCopy )
497 {
498 wxLogTrace( traceMultichannelTool, wxT("skipping copy to RA '%s' (disabled in dialog)\n"),
499 targetArea.first->m_ruleName );
500 continue;
501 }
502
503 if( !targetArea.second.m_isOk )
504 continue;
505
506
507 if( !copyRuleAreaContents( targetArea.second.m_matchingComponents, &commit, m_areas.m_refRA,
508 targetArea.first, m_areas.m_options, targetArea.second.m_affectedItems,
509 targetArea.second.m_groupableItems ) )
510 {
511 auto errMsg = wxString::Format(
512 _( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
514 targetArea.first->m_area->GetZoneName() );
515
516 commit.Revert();
517
518 if( Pgm().IsGUI() )
519 {
520 frame()->ShowInfoBarError( errMsg, true );
521 }
522
523 return -1;
524 }
525 totalCopied++;
526 }
527
528
529 commit.Push( _( "Repeat layout" ) );
530
532 {
533 BOARD_COMMIT grpCommit( GetManager(), true );
534
535 for( auto& targetArea : m_areas.m_compatMap )
536 {
537 pruneExistingGroups( grpCommit, targetArea.second.m_affectedItems );
538
539 PCB_GROUP* grp = new PCB_GROUP( board() );
540
541 grpCommit.Add( grp );
542
543 for( BOARD_ITEM* item : targetArea.second.m_groupableItems )
544 {
545 grpCommit.Stage( item, CHT_GROUP );
546 }
547 }
548
549 grpCommit.Push( _( "Group repeated items" ) );
550 }
551
552
553 if( Pgm().IsGUI() )
554 {
555 frame()->ShowInfoBarMsg( wxString::Format( _( "Copied to %d Rule Areas." ), totalCopied ),
556 true );
557 }
558 return 0;
559}
560
561
562wxString MULTICHANNEL_TOOL::stripComponentIndex( const wxString& aRef ) const
563{
564 wxString rv;
565
566 // fixme: i'm pretty sure this can be written in a simpler way, but I really suck at figuring
567 // out which wx's built in functions would do it for me. And I hate regexps :-)
568 for( auto k : aRef )
569 {
570 if( !k.IsAscii() )
571 break;
572 char c;
573 k.GetAsChar( &c );
574
575 if( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c == '_' ) )
576 rv.Append( k );
577 else
578 break;
579 }
580
581 return rv;
582}
583
584
585int MULTICHANNEL_TOOL::findRoutedConnections( std::set<BOARD_ITEM*>& aOutput,
586 std::shared_ptr<CONNECTIVITY_DATA> aConnectivity,
587 const SHAPE_POLY_SET& aRAPoly,
588 RULE_AREA* aRA,
589 FOOTPRINT* aFp,
590 const REPEAT_LAYOUT_OPTIONS& aOpts ) const
591{
592 std::set<BOARD_ITEM*> conns;
593
594 for( PAD* pad : aFp->Pads() )
595 {
596 auto connectedItems = aConnectivity->GetConnectedItems( pad, EXCLUDE_ZONES | IGNORE_NETS );
597
598 for( BOARD_CONNECTED_ITEM* item : connectedItems )
599 conns.insert( item );
600 }
601
602 int count = 0;
603
604 for( BOARD_ITEM* item : conns )
605 {
606 // fixme: respect layer sets assigned to each RA
607
608 if( item->Type() == PCB_PAD_T )
609 continue;
610
611 std::shared_ptr<SHAPE> effShape = item->GetEffectiveShape( item->GetLayer() );
612
613 if( effShape->Collide( &aRAPoly, 0 ) )
614 {
615 aOutput.insert( item );
616 count++;
617 }
618 }
619
620 // The user also will consider tracks and vias that are inside the source area but
621 // not connected to any of the source pads to count as "routing" (e.g. stitching vias)
622
624 PCBEXPR_UCODE ucode;
625 PCBEXPR_CONTEXT ctx, preflightCtx;
626
627 auto reportError = [&]( const wxString& aMessage, int aOffset )
628 {
629 wxLogTrace( traceMultichannelTool, wxT( "ERROR: %s"), aMessage );
630 };
631
632 ctx.SetErrorCallback( reportError );
633 preflightCtx.SetErrorCallback( reportError );
634 compiler.SetErrorCallback( reportError );
635
636 bool restoreBlankName = false;
637
638 if( aRA->m_area->GetZoneName().IsEmpty() )
639 {
640 restoreBlankName = true;
641 aRA->m_area->SetZoneName( aRA->m_area->m_Uuid.AsString() );
642 }
643
644 wxString ruleText = wxString::Format( wxT( "A.enclosedByArea('%s')" ),
645 aRA->m_area->GetZoneName() );
646
647 auto testAndAdd =
648 [&]( BOARD_ITEM* aItem )
649 {
650 if( aOutput.contains( aItem ) )
651 return;
652
653 ctx.SetItems( aItem, aItem );
654 auto val = ucode.Run( &ctx );
655
656 if( val->AsDouble() != 0.0 )
657 {
658 aOutput.insert( aItem );
659 count++;
660 }
661 };
662
663 if( compiler.Compile( ruleText, &ucode, &preflightCtx ) )
664 {
665 for( PCB_TRACK* track : board()->Tracks() )
666 testAndAdd( track );
667 }
668
669 if( restoreBlankName )
670 aRA->m_area->SetZoneName( wxEmptyString );
671
672 return count;
673}
674
675
677 BOARD_COMMIT* aCommit,
678 RULE_AREA* aRefArea, RULE_AREA* aTargetArea,
680 std::unordered_set<BOARD_ITEM*>& aAffectedItems,
681 std::unordered_set<BOARD_ITEM*>& aGroupableItems )
682{
683 // copy RA shapes first
684 SHAPE_LINE_CHAIN refOutline = aRefArea->m_area->Outline()->COutline( 0 );
685 SHAPE_LINE_CHAIN targetOutline = aTargetArea->m_area->Outline()->COutline( 0 );
686
687 VECTOR2I disp = aTargetArea->m_center - aRefArea->m_center;
688
689 SHAPE_POLY_SET refPoly;
690 refPoly.AddOutline( refOutline );
691 refPoly.CacheTriangulation( false );
692
693 SHAPE_POLY_SET targetPoly;
694
695 SHAPE_LINE_CHAIN newTargetOutline( refOutline );
696 newTargetOutline.Move( disp );
697 targetPoly.AddOutline( newTargetOutline );
698 targetPoly.CacheTriangulation( false );
699
700 auto connectivity = board()->GetConnectivity();
701
702 aCommit->Modify( aTargetArea->m_area );
703
704 aAffectedItems.insert( aTargetArea->m_area );
705 aGroupableItems.insert( aTargetArea->m_area );
706
707 if( aOpts.m_copyRouting )
708 {
709 std::set<BOARD_ITEM*> refRouting;
710 std::set<BOARD_ITEM*> targetRouting;
711
712 wxLogTrace( traceMultichannelTool, wxT("copying routing: %d fps\n"), (int) aMatches.size() );
713
714 for( auto& fpPair : aMatches )
715 {
716 findRoutedConnections( targetRouting, connectivity, targetPoly, aTargetArea,
717 fpPair.second, aOpts );
718 findRoutedConnections( refRouting, connectivity, refPoly, aRefArea, fpPair.first,
719 aOpts );
720
721 wxLogTrace( traceMultichannelTool, wxT("target-routes %d\n"), (int) targetRouting.size() );
722 }
723
724 for( BOARD_ITEM* item : targetRouting )
725 {
726 if( item->IsLocked() && !aOpts.m_includeLockedItems )
727 continue;
728
729 // item already removed
730 if( aCommit->GetStatus( item ) != 0 )
731 continue;
732
733 if( aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
734 {
735 aAffectedItems.insert( item );
736 aCommit->Remove( item );
737 }
738 }
739
740 for( BOARD_ITEM* item : refRouting )
741 {
742 if( !aRefArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
743 continue;
744
745 if( !aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
746 continue;
747
748 BOARD_ITEM* copied = static_cast<BOARD_ITEM*>( item->Clone() );
749
750 copied->Move( disp );
751 copied->SetParentGroup( nullptr );
752 aGroupableItems.insert( copied );
753 aCommit->Add( copied );
754 }
755 }
756
757 if( aOpts.m_copyOtherItems )
758 {
759 std::set<BOARD_ITEM*> sourceItems;
760 std::set<BOARD_ITEM*> targetItems;
761
762 findOtherItemsInRuleArea( aRefArea->m_area, sourceItems );
763 findOtherItemsInRuleArea( aTargetArea->m_area, targetItems );
764
765 for( BOARD_ITEM* item : targetItems )
766 {
767 if( item->Type() == PCB_TEXT_T && item->GetParent()
768 && item->GetParent()->Type() == PCB_FOOTPRINT_T )
769 continue;
770
771 if( item->IsLocked() && !aOpts.m_includeLockedItems )
772 continue;
773
774 // item already removed
775 if( aCommit->GetStatus( item ) != 0 )
776 continue;
777
778 if( item->Type() != PCB_ZONE_T )
779 {
780 if( aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
781 {
782 aAffectedItems.insert( item );
783 aCommit->Remove( item );
784 }
785 }
786 else
787 {
788 ZONE* zone = static_cast<ZONE*>( item );
789
790 // Check all zone layers are included in the rule area
791 bool layerMismatch = false;
792 LSET zoneLayers = zone->GetLayerSet();
793
794 for( const PCB_LAYER_ID& layer : zoneLayers )
795 {
796 if( !aTargetArea->m_area->GetLayerSet().Contains( layer ) )
797 layerMismatch = true;
798 }
799
800 if( !layerMismatch )
801 {
802 aAffectedItems.insert( zone );
803 aCommit->Remove( zone );
804 }
805 }
806 }
807
808 for( BOARD_ITEM* item : sourceItems )
809 {
810 if( item->Type() == PCB_TEXT_T && item->GetParent()
811 && item->GetParent()->Type() == PCB_FOOTPRINT_T )
812 continue;
813
814 BOARD_ITEM* copied = nullptr;
815
816 if( item->Type() != PCB_ZONE_T )
817 {
818 if( !aRefArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
819 continue;
820 if( !aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
821 continue;
822
823 if( item->Type() == PCB_GROUP_T )
824 {
825 copied = static_cast<PCB_GROUP*>( item )->DeepClone();
826 }
827 else
828 {
829 copied = static_cast<BOARD_ITEM*>( item->Clone() );
830 }
831 }
832 else
833 {
834 ZONE* zone = static_cast<ZONE*>( item );
835
836 // Check all zone layers are included in the rule area
837 bool layerMismatch = false;
838 LSET zoneLayers = zone->GetLayerSet();
839
840 for( const PCB_LAYER_ID& layer : zoneLayers )
841 {
842 if( !aRefArea->m_area->GetLayerSet().Contains( layer )
843 || !aTargetArea->m_area->GetLayerSet().Contains( layer ) )
844 {
845 layerMismatch = true;
846 }
847 }
848
849 if( layerMismatch )
850 continue;
851
852 ZONE* targetZone = static_cast<ZONE*>( item->Clone() );
853 fixupZoneNets( zone, targetZone, aMatches );
854
855 copied = targetZone;
856 }
857
858 if( copied )
859 {
860 copied->ClearFlags();
861 copied->SetParentGroup( nullptr );
862 copied->Move( disp );
863 aGroupableItems.insert( copied );
864 aCommit->Add( copied );
865 }
866 }
867 }
868
869 aTargetArea->m_area->RemoveAllContours();
870 aTargetArea->m_area->AddPolygon( newTargetOutline );
871 aTargetArea->m_area->UnHatchBorder();
872 aTargetArea->m_area->HatchBorder();
873
874 if( aOpts.m_copyPlacement )
875 {
876 for( auto& fpPair : aMatches )
877 {
878 FOOTPRINT* refFP = fpPair.first;
879 FOOTPRINT* targetFP = fpPair.second;
880
881 if( !aRefArea->m_area->GetLayerSet().Contains( refFP->GetLayer() ) )
882 {
883 wxLogTrace( traceMultichannelTool, wxT( "discard ref:%s (ref layer)\n" ),
884 refFP->GetReference() );
885 continue;
886 }
887 if( !aTargetArea->m_area->GetLayerSet().Contains( refFP->GetLayer() ) )
888 {
889 wxLogTrace( traceMultichannelTool, wxT( "discard ref:%s (target layer)\n" ),
890 refFP->GetReference() );
891 continue;
892 }
893
894 // Ignore footprints outside of the rule area
895 if( !refFP->GetEffectiveShape( refFP->GetLayer() )->Collide( &refPoly, 0 ) )
896 continue;
897
898 if( targetFP->IsLocked() && !aOpts.m_includeLockedItems )
899 continue;
900
901 aCommit->Modify( targetFP );
902
903 targetFP->SetLayerAndFlip( refFP->GetLayer() );
904 targetFP->SetOrientation( refFP->GetOrientation() );
905 VECTOR2I targetPos = refFP->GetPosition() + disp;
906 targetFP->SetPosition( targetPos );
907
908 for( PCB_FIELD* refField : refFP->GetFields() )
909 {
910 if( !refField->IsVisible() )
911 continue;
912
913 PCB_FIELD* targetField = targetFP->GetField( refField->GetName() );
914 wxCHECK2( targetField, continue );
915
916 targetField->SetAttributes( refField->GetAttributes() );
917 targetField->SetPosition( refField->GetPosition() + disp );
918 targetField->SetIsKnockout( refField->IsKnockout() );
919 }
920
921 aAffectedItems.insert( targetFP );
922 aGroupableItems.insert( targetFP );
923 }
924 }
925
926 return true;
927}
928
929
934void MULTICHANNEL_TOOL::fixupZoneNets( ZONE* aRefZone, ZONE* aTargetZone,
935 TMATCH::COMPONENT_MATCHES& aComponentMatches )
936{
937 auto connectivity = board()->GetConnectivity();
938 const std::vector<BOARD_CONNECTED_ITEM*> refZoneConnectedPads =
939 connectivity->GetNetItems( aRefZone->GetNetCode(), { PCB_PAD_T } );
940
941 for( const BOARD_CONNECTED_ITEM* refConItem : refZoneConnectedPads )
942 {
943 if( refConItem->Type() != PCB_PAD_T )
944 continue;
945
946 const PAD* refPad = static_cast<const PAD*>( refConItem );
947 FOOTPRINT* sourceFootprint = refPad->GetParentFootprint();
948
949 if( aComponentMatches.contains( sourceFootprint ) )
950 {
951 const FOOTPRINT* targetFootprint = aComponentMatches[sourceFootprint];
952 std::vector<const PAD*> targetFpPads = targetFootprint->GetPads( refPad->GetNumber() );
953
954 if( !targetFpPads.empty() )
955 {
956 int targetNetCode = targetFpPads[0]->GetNet()->GetNetCode();
957 aTargetZone->SetNetCode( targetNetCode );
958
959 break;
960 }
961 }
962 }
963}
964
965
967 RULE_AREA_COMPAT_DATA& aMatches )
968{
969 using namespace TMATCH;
970
971 std::unique_ptr<CONNECTION_GRAPH> cgRef ( CONNECTION_GRAPH::BuildFromFootprintSet( aRefArea->m_raFootprints ) );
972 std::unique_ptr<CONNECTION_GRAPH> cgTarget ( CONNECTION_GRAPH::BuildFromFootprintSet( aTargetArea->m_raFootprints ) );
973
974 auto status = cgRef->FindIsomorphism( cgTarget.get(), aMatches.m_matchingComponents );
975
976 switch( status )
977 {
978 case CONNECTION_GRAPH::ST_OK:
979 aMatches.m_isOk = true;
980 aMatches.m_errorMsg = _("OK");
981 break;
982 case CONNECTION_GRAPH::ST_EMPTY:
983 aMatches.m_isOk = false;
984 aMatches.m_errorMsg = _("One or both of the areas has no components assigned.");
985 break;
986 case CONNECTION_GRAPH::ST_COMPONENT_COUNT_MISMATCH:
987 aMatches.m_isOk = false;
988 aMatches.m_errorMsg = _("Component count mismatch");
989 break;
990 case CONNECTION_GRAPH::ST_ITERATION_COUNT_EXCEEDED:
991 aMatches.m_isOk = false;
992 aMatches.m_errorMsg = _("Iteration count exceeded (timeout)");
993 break;
994 case CONNECTION_GRAPH::ST_TOPOLOGY_MISMATCH:
995 aMatches.m_isOk = false;
996 aMatches.m_errorMsg = _("Topology mismatch");
997 break;
998 default:
999 break;
1000 }
1001
1002 return ( status == TMATCH::CONNECTION_GRAPH::ST_OK );
1003}
1004
1005
1007 const std::unordered_set<BOARD_ITEM*>& aItemsToRemove )
1008{
1009 std::deque<PCB_GROUP*> pending ( board()->Groups() );
1010 while( !pending.empty() )
1011 {
1012 auto grp = pending.front();
1013 pending.pop_front();
1014
1015 std::unordered_set<BOARD_ITEM*>& grpItems = grp->GetItems();
1016 size_t n_erased = 0;
1017
1018 for( BOARD_ITEM* refItem : grpItems )
1019 {
1020
1021 if( refItem->Type() == PCB_GROUP_T )
1022 pending.push_back( static_cast<PCB_GROUP*>(refItem) );
1023
1024 for( BOARD_ITEM* testItem : aItemsToRemove )
1025 {
1026 if( refItem->m_Uuid == testItem->m_Uuid )
1027 {
1028 aCommit.Stage( refItem, CHT_UNGROUP );
1029 n_erased++;
1030 }
1031 }
1032 }
1033
1034 if( n_erased == grpItems.size() )
1035 {
1036 aCommit.Stage( grp, CHT_REMOVE );
1037 }
1038
1039 }
1040
1041 return false;
1042}
1043
1044
1046{
1047 if( Pgm().IsGUI() )
1048 {
1050
1051 if( m_areas.m_areas.size() <= 1 )
1052 {
1053 frame()->ShowInfoBarError( _( "Cannot auto-generate any placement areas because the "
1054 "schematic has only one or no hierarchical sheet(s) or "
1055 "component classes." ),
1056 true );
1057 return 0;
1058 }
1059
1061 int ret = dialog.ShowModal();
1062
1063 if( ret != wxID_OK )
1064 return 0;
1065 }
1066
1067 for( ZONE* zone : board()->Zones() )
1068 {
1069 if( !zone->GetIsRuleArea() )
1070 continue;
1071 if( !zone->GetRuleAreaPlacementEnabled() )
1072 continue;
1073
1074 std::set<FOOTPRINT*> components;
1075 identifyComponentsInRuleArea( zone, components );
1076
1077 if( components.empty() )
1078 continue;
1079
1080 for( RULE_AREA& ra : m_areas.m_areas )
1081 {
1082 if( components == ra.m_components )
1083 {
1084 if( zone->GetRuleAreaPlacementSourceType()
1085 == RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME )
1086 {
1087 wxLogTrace(
1089 wxT( "Placement rule area for sheet '%s' already exists as '%s'\n" ),
1090 ra.m_sheetPath, zone->GetZoneName() );
1091 }
1092 else
1093 {
1094 wxLogTrace( traceMultichannelTool,
1095 wxT( "Placement rule area for component class '%s' already exists "
1096 "as '%s'\n" ),
1097 ra.m_componentClass, zone->GetZoneName() );
1098 }
1099
1100 ra.m_oldArea = zone;
1101 ra.m_existsAlready = true;
1102 }
1103 }
1104 }
1105
1106 wxLogTrace( traceMultichannelTool,
1107 wxT( "%d placement areas found\n" ), (int) m_areas.m_areas.size() );
1108
1109 BOARD_COMMIT commit( GetManager(), true );
1110
1111 for( RULE_AREA& ra : m_areas.m_areas )
1112 {
1113 if( !ra.m_generateEnabled )
1114 continue;
1115
1117 continue;
1118
1119 SHAPE_LINE_CHAIN raOutline = buildRAOutline( ra.m_components, 100000 );
1120
1121 std::unique_ptr<ZONE> newZone( new ZONE( board() ) );
1122
1123 if( ra.m_sourceType == RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME )
1124 {
1125 newZone->SetZoneName(
1126 wxString::Format( wxT( "auto-placement-area-%s" ), ra.m_sheetPath ) );
1127 }
1128 else
1129 {
1130 newZone->SetZoneName(
1131 wxString::Format( wxT( "auto-placement-area-%s" ), ra.m_componentClass ) );
1132 }
1133
1134 wxLogTrace( traceMultichannelTool, wxT( "Generated rule area '%s' (%d components)\n" ),
1135 newZone->GetZoneName(), (int) ra.m_components.size() );
1136
1137 newZone->SetIsRuleArea( true );
1138 newZone->SetLayerSet( LSET::AllCuMask() );
1139 newZone->SetRuleAreaPlacementEnabled( true );
1140 newZone->SetDoNotAllowZoneFills( false );
1141 newZone->SetDoNotAllowVias( false );
1142 newZone->SetDoNotAllowTracks( false );
1143 newZone->SetDoNotAllowPads( false );
1144 newZone->SetDoNotAllowFootprints( false );
1145
1146 if( ra.m_sourceType == RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME )
1147 {
1148 newZone->SetRuleAreaPlacementSourceType( RULE_AREA_PLACEMENT_SOURCE_TYPE::SHEETNAME );
1149 newZone->SetRuleAreaPlacementSource( ra.m_sheetPath );
1150 }
1151 else
1152 {
1153 newZone->SetRuleAreaPlacementSourceType(
1154 RULE_AREA_PLACEMENT_SOURCE_TYPE::COMPONENT_CLASS );
1155 newZone->SetRuleAreaPlacementSource( ra.m_componentClass );
1156 }
1157
1158 newZone->AddPolygon( raOutline );
1159 newZone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH );
1160
1161 if( ra.m_existsAlready )
1162 {
1163 commit.Remove( ra.m_oldArea );
1164 }
1165
1166 ra.m_area = newZone.get();
1167 commit.Add( newZone.release() );
1168
1169 }
1170
1171 commit.Push( _( "Auto-generate placement rule areas" ) );
1172
1173 // fixme: handle corner cases where the items belonging to a Rule Area already
1174 // belong to other groups.
1175
1177 {
1178 // fixme: sth gets weird when creating new zones & grouping them within a single COMMIT
1179 BOARD_COMMIT grpCommit( GetManager(), true );
1180
1181 for( RULE_AREA& ra : m_areas.m_areas )
1182 {
1183 if( !ra.m_generateEnabled )
1184 continue;
1185
1187 continue;
1188
1189 std::unordered_set<BOARD_ITEM*> toPrune;
1190
1191 std::copy( ra.m_components.begin(), ra.m_components.end(),
1192 std::inserter( toPrune, toPrune.begin() ) );
1193
1194 if( ra.m_existsAlready )
1195 toPrune.insert( ra.m_area );
1196
1197 pruneExistingGroups( grpCommit, toPrune );
1198
1199 PCB_GROUP* grp = new PCB_GROUP( board() );
1200
1201 grpCommit.Add( grp );
1202 grpCommit.Stage( ra.m_area, CHT_GROUP );
1203
1204 for( FOOTPRINT* fp : ra.m_components )
1205 {
1206 grpCommit.Stage( fp, CHT_GROUP );
1207 }
1208 }
1209 grpCommit.Push( _( "Group components with their placement rule areas" ) );
1210 }
1211
1212 return true;
1213}
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
Add a change of the item aItem of type aChangeType to the change list.
virtual void Revert() override
Revert the commit by restoring the modified items state.
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:78
virtual void SetIsKnockout(bool aKnockout)
Definition: board_item.h:323
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:305
const ZONES & Zones() const
Definition: board.h:342
const TRACKS & Tracks() const
Definition: board.h:336
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:495
constexpr BOX2< Vec > GetInflated(coord_type aDx, coord_type aDy) const
Get a new rectangle that is this one, inflated by aDx and aDy.
Definition: box2.h:638
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition: commit.h:74
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition: commit.h:92
virtual COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr)
Add a change of the item aItem of type aChangeType to the change list.
Definition: commit.cpp:48
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Modify a given item in the model.
Definition: commit.h:108
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition: commit.h:80
int GetStatus(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Returns status of an item.
Definition: commit.cpp:130
A lightweight representation of a component class.
const std::vector< COMPONENT_CLASS * > & GetConstituentClasses() const
Fetches a vector of the constituent classes for this (effective) class.
int ShowModal() override
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:95
const KIID m_Uuid
Definition: eda_item.h:494
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition: eda_item.h:180
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition: eda_text.cpp:426
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2456
EDA_ANGLE GetOrientation() const
Definition: footprint.h:232
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2538
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: footprint.cpp:2951
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
Definition: footprint.cpp:582
std::deque< PAD * > & Pads()
Definition: footprint.h:211
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:241
bool IsLocked() const override
Definition: footprint.h:416
void SetLayerAndFlip(PCB_LAYER_ID aLayer)
Used as Layer property setter – performs a flip if necessary to set the footprint layer.
Definition: footprint.cpp:2388
std::vector< const PAD * > GetPads(const wxString &aPadNumber, const PAD *aIgnore=nullptr) const
Definition: footprint.cpp:1991
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
Definition: footprint.cpp:627
const wxString & GetReference() const
Definition: footprint.h:619
VECTOR2I GetPosition() const override
Definition: footprint.h:229
wxString AsString() const
Definition: kiid.cpp:246
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
VALUE * Run(CONTEXT *ctx)
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:37
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:572
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition: lset.h:63
int CheckRACompatibility(ZONE *aRefZone)
std::set< FOOTPRINT * > queryComponentsInSheet(wxString aSheetName) const
int findRoutedConnections(std::set< BOARD_ITEM * > &aOutput, std::shared_ptr< CONNECTIVITY_DATA > aConnectivity, const SHAPE_POLY_SET &aRAPoly, RULE_AREA *aRA, FOOTPRINT *aFp, const REPEAT_LAYOUT_OPTIONS &aOpts) const
int repeatLayout(const TOOL_EVENT &aEvent)
void UpdatePickedItem(const EDA_ITEM *aItem) override
void setTransitions() override
This method is meant to be overridden in order to specify handlers for events.
const SHAPE_LINE_CHAIN buildRAOutline(std::set< FOOTPRINT * > &aFootprints, int aMargin)
wxString stripComponentIndex(const wxString &aRef) const
bool resolveConnectionTopology(RULE_AREA *aRefArea, RULE_AREA *aTargetArea, RULE_AREA_COMPAT_DATA &aMatches)
RULE_AREAS_DATA m_areas
bool pruneExistingGroups(COMMIT &aCommit, const std::unordered_set< BOARD_ITEM * > &aItemsToCheck)
int RepeatLayout(const TOOL_EVENT &aEvent, ZONE *aRefZone)
int AutogenerateRuleAreas(const TOOL_EVENT &aEvent)
bool identifyComponentsInRuleArea(ZONE *aRuleArea, std::set< FOOTPRINT * > &aComponents)
void fixupZoneNets(ZONE *aRefZone, ZONE *aTargetZone, TMATCH::COMPONENT_MATCHES &aComponentMatches)
Attempts to modify the assigned net of a copied zone.
std::set< FOOTPRINT * > queryComponentsInComponentClass(const wxString &aComponentClassName) const
RULE_AREA * findRAByName(const wxString &aName)
bool copyRuleAreaContents(TMATCH::COMPONENT_MATCHES &aMatches, BOARD_COMMIT *aCommit, RULE_AREA *aRefArea, RULE_AREA *aTargetArea, REPEAT_LAYOUT_OPTIONS aOpts, std::unordered_set< BOARD_ITEM * > &aAffectedItems, std::unordered_set< BOARD_ITEM * > &aGroupableItems)
bool findOtherItemsInRuleArea(ZONE *aRuleArea, std::set< BOARD_ITEM * > &aItems)
Definition: pad.h:54
const wxString & GetNumber() const
Definition: pad.h:136
void SetItems(BOARD_ITEM *a, BOARD_ITEM *b=nullptr)
static TOOL_ACTION repeatLayout
Definition: pcb_actions.h:612
static TOOL_ACTION generatePlacementRuleAreas
Definition: pcb_actions.h:613
static TOOL_ACTION selectItemInteractively
Selection of reference points/items.
Definition: pcb_actions.h:332
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
virtual void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_text.h:89
T * frame() const
BOARD * board() const
const PCB_SELECTION & selection() const
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
Represent a set of closed polygons.
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index.
virtual void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
TOOL_MANAGER * GetManager() const
Return the instance of TOOL_MANAGER that takes care of the tool.
Definition: tool_base.h:146
TOOL_MANAGER * m_toolMgr
Definition: tool_base.h:220
Generic, UI-independent tool event.
Definition: tool_event.h:168
void Go(int(T::*aStateFunc)(const TOOL_EVENT &), const TOOL_EVENT_LIST &aConditions=TOOL_EVENT(TC_ANY, TA_ANY))
Define which state (aStateFunc) to go when a certain event arrives (aConditions).
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:150
Handle a list of polygons defining a copper zone.
Definition: zone.h:74
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:752
wxString GetRuleAreaPlacementSource() const
Definition: zone.h:757
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition: zone.cpp:1111
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition: zone.cpp:1231
bool GetRuleAreaPlacementEnabled() const
Definition: zone.h:754
SHAPE_POLY_SET * Outline()
Definition: zone.h:368
const wxString & GetZoneName() const
Definition: zone.h:163
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:136
RULE_AREA_PLACEMENT_SOURCE_TYPE GetRuleAreaPlacementSourceType() const
Definition: zone.h:759
void SetZoneName(const wxString &aName)
Definition: zone.h:164
void UnHatchBorder()
Clear the zone's hatch.
Definition: zone.cpp:1225
void RemoveAllContours(void)
Definition: zone.h:582
@ CHT_GROUP
Definition: commit.h:45
@ CHT_REMOVE
Definition: commit.h:43
@ CHT_UNGROUP
Definition: commit.h:46
#define EXCLUDE_ZONES
#define IGNORE_NETS
Function GetConnectedItems() Returns a list of items connected to a source item aItem.
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
Definition: convex_hull.cpp:87
#define _(s)
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
static const wxString traceMultichannelTool
SHAPE_LINE_CHAIN RectifyPolygon(const SHAPE_LINE_CHAIN &aPoly)
void CollectBoxCorners(const BOX2I &aBox, std::vector< VECTOR2I > &aCorners)
Add the 4 corners of a BOX2I to a vector.
Definition: shape_utils.cpp:84
std::map< FOOTPRINT *, FOOTPRINT * > COMPONENT_MATCHES
Definition: topo_match.h:149
Class to handle a set of BOARD_ITEMs.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1071
see class PGM_BASE
Utility functions for working with shapes.
std::unordered_map< RULE_AREA *, RULE_AREA_COMPAT_DATA > m_compatMap
REPEAT_LAYOUT_OPTIONS m_options
std::vector< RULE_AREA > m_areas
TMATCH::COMPONENT_MATCHES m_matchingComponents
VECTOR2I m_center
RULE_AREA_PLACEMENT_SOURCE_TYPE m_sourceType
wxString m_sheetName
wxString m_componentClass
bool m_existsAlready
std::set< FOOTPRINT * > m_raFootprints
ZONE * m_oldArea
std::set< FOOTPRINT * > m_components
wxString m_ruleName
wxString m_sheetPath
bool m_generateEnabled
bool copied
@ PCB_GROUP_T
class PCB_GROUP, a set of BOARD_ITEMs
Definition: typeinfo.h:110
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
@ PCB_TEXT_T
class PCB_TEXT, text on a layer
Definition: typeinfo.h:92
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint
Definition: typeinfo.h:86
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87