KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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>
39#include <footprint.h>
43#include <optional>
44#include <algorithm>
46#include <pcb_track.h>
47#include <tool/tool_manager.h>
49#include <random>
50#include <core/profile.h>
51#include <wx/log.h>
52#include <pgm_base.h>
53
54
55#define MULTICHANNEL_EXTRA_DEBUG
56
57static const wxString traceMultichannelTool = wxT( "MULTICHANNEL_TOOL" );
58
59
61{
62}
63
64
69
70
76
77
79 std::set<FOOTPRINT*>& aComponents )
80{
81 if( !aRuleArea || !aRuleArea->m_zone )
82 return false;
83
84 // When we're copying the layout of a design block, we are provided an exact list of items
85 // rather than querying the board for items that are inside the area.
87 {
88 // Get all board connected items that are from the design bloc
89 for( EDA_ITEM* item : aRuleArea->m_designBlockItems )
90 {
91 if( item->Type() == PCB_FOOTPRINT_T )
92 aComponents.insert( static_cast<FOOTPRINT*>( item ) );
93 }
94
95 return (int) aComponents.size();
96 }
97
98
100 PCBEXPR_UCODE ucode;
101 PCBEXPR_CONTEXT ctx, preflightCtx;
102
103 auto reportError =
104 [&]( const wxString& aMessage, int aOffset )
105 {
106 wxLogTrace( traceMultichannelTool, wxT( "ERROR: %s"), aMessage );
107 };
108
109 ctx.SetErrorCallback( reportError );
110 preflightCtx.SetErrorCallback( reportError );
111 compiler.SetErrorCallback( reportError );
112 //compiler.SetDebugReporter( m_reporter );
113
114 wxLogTrace( traceMultichannelTool, wxT( "rule area '%s'" ), aRuleArea->m_zone->GetZoneName() );
115
116 wxString ruleText;
117
118 switch( aRuleArea->m_zone->GetPlacementAreaSourceType() )
119 {
121 ruleText = wxT( "A.memberOfSheetOrChildren('" ) + aRuleArea->m_zone->GetPlacementAreaSource() + wxT( "')" );
122 break;
124 ruleText = wxT( "A.hasComponentClass('" ) + aRuleArea->m_zone->GetPlacementAreaSource() + wxT( "')" );
125 break;
127 ruleText = wxT( "A.memberOfGroup('" ) + aRuleArea->m_zone->GetPlacementAreaSource() + wxT( "')" );
128 break;
130 // For design blocks, handled above outside the rules system
131 break;
132 }
133
134 auto ok = compiler.Compile( ruleText, &ucode, &preflightCtx );
135
136 if( !ok )
137 return false;
138
139 for( FOOTPRINT* fp : board()->Footprints() )
140 {
141 ctx.SetItems( fp, fp );
142 LIBEVAL::VALUE* val = ucode.Run( &ctx );
143
144 if( val->AsDouble() != 0.0 )
145 {
146 wxLogTrace( traceMultichannelTool, wxT( " - %s [sheet %s]" ),
147 fp->GetReference(),
148 fp->GetSheetname() );
149
150 aComponents.insert( fp );
151 }
152 }
153
154 return true;
155}
156
157
158bool MULTICHANNEL_TOOL::findOtherItemsInRuleArea( RULE_AREA* aRuleArea, std::set<BOARD_ITEM*>& aItems )
159{
160 if( !aRuleArea || !aRuleArea->m_zone )
161 return false;
162
163 // When we're copying the layout of a design block, we are provided an exact list of items
164 // rather than querying the board for items that are inside the area.
166 {
167 // Get all board items that aren't footprints or connected items,
168 // since they'll be handled in the the other findXInRuleArea routines
169 for( EDA_ITEM* item : aRuleArea->m_designBlockItems )
170 {
171 if( item->Type() == PCB_FOOTPRINT_T )
172 continue;
173
174 if( dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
175 continue;
176
177 if( item->IsBOARD_ITEM() )
178 aItems.insert( static_cast<BOARD_ITEM*>( item ) );
179 }
180
181 return (int) aItems.size();
182 }
183
184 std::vector<BOARD_ITEM*> result;
185
187 PCBEXPR_UCODE ucode;
188 PCBEXPR_CONTEXT ctx, preflightCtx;
189
190 auto reportError =
191 [&]( const wxString& aMessage, int aOffset )
192 {
193 wxLogTrace( traceMultichannelTool, wxT( "ERROR: %s"), aMessage );
194 };
195
196 ctx.SetErrorCallback( reportError );
197 preflightCtx.SetErrorCallback( reportError );
198 compiler.SetErrorCallback( reportError );
199
200 bool restoreBlankName = false;
201
202 if( aRuleArea->m_zone->GetZoneName().IsEmpty() )
203 {
204 restoreBlankName = true;
205 aRuleArea->m_zone->SetZoneName( aRuleArea->m_zone->m_Uuid.AsString() );
206 }
207
208 wxString ruleText = wxString::Format( wxT( "A.enclosedByArea('%s')" ), aRuleArea->m_zone->GetZoneName() );
209
210 if( !compiler.Compile( ruleText, &ucode, &preflightCtx ) )
211 {
212 if( restoreBlankName )
213 aRuleArea->m_zone->SetZoneName( wxEmptyString );
214
215 return false;
216 }
217
218 auto testAndAdd =
219 [&]( BOARD_ITEM* aItem )
220 {
221 ctx.SetItems( aItem, aItem );
222 auto val = ucode.Run( &ctx );
223
224 if( val->AsDouble() != 0.0 )
225 aItems.insert( aItem );
226 };
227
228 for( ZONE* zone : board()->Zones() )
229 {
230 if( zone == aRuleArea->m_zone )
231 continue;
232
233 testAndAdd( zone );
234 }
235
236 for( BOARD_ITEM* drawing : board()->Drawings() )
237 testAndAdd( drawing );
238
239 for( PCB_GROUP* group : board()->Groups() )
240 {
241 // A group is cloned in its entirety if *all* children are contained
242 bool addGroup = true;
243
244 group->RunOnChildren(
245 [&]( BOARD_ITEM* aItem )
246 {
247 if( aItem->IsType( { PCB_ZONE_T, PCB_SHAPE_T, PCB_DIMENSION_T } ) )
248 {
249 ctx.SetItems( aItem, aItem );
250 LIBEVAL::VALUE* val = ucode.Run( &ctx );
251
252 if( val->AsDouble() == 0.0 )
253 addGroup = false;
254 }
255 },
257
258 if( addGroup )
259 aItems.insert( group );
260 }
261
262 if( restoreBlankName )
263 aRuleArea->m_zone->SetZoneName( wxEmptyString );
264
265 return true;
266}
267
268
269std::set<FOOTPRINT*> MULTICHANNEL_TOOL::queryComponentsInSheet( wxString aSheetName ) const
270{
271 std::set<FOOTPRINT*> rv;
272
273 if( aSheetName.EndsWith( wxT( "/" ) ) )
274 aSheetName.RemoveLast();
275
276 for( FOOTPRINT* fp : board()->Footprints() )
277 {
278 auto sn = fp->GetSheetname();
279 if( sn.EndsWith( wxT( "/" ) ) )
280 sn.RemoveLast();
281
282 if( sn == aSheetName )
283 rv.insert( fp );
284 }
285
286 return rv;
287}
288
289
290std::set<FOOTPRINT*>
291MULTICHANNEL_TOOL::queryComponentsInComponentClass( const wxString& aComponentClassName ) const
292{
293 std::set<FOOTPRINT*> rv;
294
295 for( FOOTPRINT* fp : board()->Footprints() )
296 {
297 if( fp->GetComponentClass()->ContainsClassName( aComponentClassName ) )
298 rv.insert( fp );
299 }
300
301 return rv;
302}
303
304
305std::set<FOOTPRINT*> MULTICHANNEL_TOOL::queryComponentsInGroup( const wxString& aGroupName ) const
306{
307 std::set<FOOTPRINT*> rv;
308
309 for( PCB_GROUP* group : board()->Groups() )
310 {
311 if( group->GetName() == aGroupName )
312 {
313 for( EDA_ITEM* item : group->GetItems() )
314 {
315 if( item->Type() == PCB_FOOTPRINT_T )
316 rv.insert( static_cast<FOOTPRINT*>( item ) );
317 }
318 }
319 }
320
321 return rv;
322}
323
324
325const SHAPE_LINE_CHAIN MULTICHANNEL_TOOL::buildRAOutline( std::set<FOOTPRINT*>& aFootprints,
326 int aMargin )
327{
328 std::vector<VECTOR2I> bbCorners;
329 bbCorners.reserve( aFootprints.size() * 4 );
330
331 for( FOOTPRINT* fp : aFootprints )
332 {
333 const BOX2I bb = fp->GetBoundingBox( false ).GetInflated( aMargin );
334 KIGEOM::CollectBoxCorners( bb, bbCorners );
335 }
336
337 std::vector<VECTOR2I> hullVertices;
338 BuildConvexHull( hullVertices, bbCorners );
339
340 SHAPE_LINE_CHAIN hull( hullVertices );
341
342 // Make the newly computed convex hull use only 90 degree segments
343 return KIGEOM::RectifyPolygon( hull );
344}
345
346
348{
349 using PathAndName = std::pair<wxString, wxString>;
350 std::set<PathAndName> uniqueSheets;
351 std::set<wxString> uniqueComponentClasses;
352 std::set<wxString> uniqueGroups;
353
354 m_areas.m_areas.clear();
355
356 for( const FOOTPRINT* fp : board()->Footprints() )
357 {
358 uniqueSheets.insert( PathAndName( fp->GetSheetname(), fp->GetSheetfile() ) );
359
360 const COMPONENT_CLASS* compClass = fp->GetComponentClass();
361
362 for( const COMPONENT_CLASS* singleClass : compClass->GetConstituentClasses() )
363 uniqueComponentClasses.insert( singleClass->GetName() );
364
365 if( fp->GetParentGroup() && !fp->GetParentGroup()->GetName().IsEmpty() )
366 uniqueGroups.insert( fp->GetParentGroup()->GetName() );
367 }
368
369 for( const PathAndName& sheet : uniqueSheets )
370 {
371 RULE_AREA ent;
372
374 ent.m_generateEnabled = false;
375 ent.m_sheetPath = sheet.first;
376 ent.m_sheetName = sheet.second;
378 m_areas.m_areas.push_back( ent );
379
380 wxLogTrace( traceMultichannelTool, wxT("found sheet '%s' @ '%s' s %d\n"),
381 ent.m_sheetName,
382 ent.m_sheetPath,
383 (int) m_areas.m_areas.size() );
384 }
385
386 for( const wxString& compClass : uniqueComponentClasses )
387 {
388 RULE_AREA ent;
389
391 ent.m_generateEnabled = false;
392 ent.m_componentClass = compClass;
394 m_areas.m_areas.push_back( ent );
395
396 wxLogTrace( traceMultichannelTool, wxT( "found component class '%s' s %d\n" ),
398 static_cast<int>( m_areas.m_areas.size() ) );
399 }
400
401 for( const wxString& groupName : uniqueGroups )
402 {
403 RULE_AREA ent;
404
406 ent.m_generateEnabled = false;
407 ent.m_groupName = groupName;
409 m_areas.m_areas.push_back( ent );
410
411 wxLogTrace( traceMultichannelTool, wxT( "found group '%s' s %d\n" ),
413 static_cast<int>( m_areas.m_areas.size() ) );
414 }
415}
416
417
419{
420 m_areas.m_areas.clear();
421
422 for( ZONE* zone : board()->Zones() )
423 {
424 if( !zone->GetIsRuleArea() )
425 continue;
426
427 if( !zone->GetPlacementAreaEnabled() )
428 continue;
429
430 RULE_AREA area;
431
432 area.m_existsAlready = true;
433 area.m_zone = zone;
434 area.m_ruleName = zone->GetZoneName();
435 area.m_center = zone->Outline()->COutline( 0 ).Centre();
436
438
439 m_areas.m_areas.push_back( area );
440
441 wxLogTrace( traceMultichannelTool, wxT( "RA '%s', %d footprints\n" ), area.m_ruleName,
442 (int) area.m_components.size() );
443 }
444
445 wxLogTrace( traceMultichannelTool, wxT( "Total RAs found: %d\n" ), (int) m_areas.m_areas.size() );
446}
447
448
450{
451 for( RULE_AREA& ra : m_areas.m_areas )
452 {
453 if( ra.m_ruleName == aName )
454 return &ra;
455 }
456
457 return nullptr;
458}
459
460
462{
464}
465
466
468{
469 std::vector<ZONE*> refRAs;
470
471 auto isSelectedItemAnRA =
472 []( EDA_ITEM* aItem ) -> ZONE*
473 {
474 if( !aItem || aItem->Type() != PCB_ZONE_T )
475 return nullptr;
476
477 ZONE* zone = static_cast<ZONE*>( aItem );
478
479 if( !zone->GetIsRuleArea() )
480 return nullptr;
481
482 if( !zone->GetPlacementAreaEnabled() )
483 return nullptr;
484
485 return zone;
486 };
487
488 for( EDA_ITEM* item : selection() )
489 {
490 if( auto zone = isSelectedItemAnRA( item ) )
491 {
492 refRAs.push_back(zone);
493 }
494 else if ( item->Type() == PCB_GROUP_T )
495 {
496 PCB_GROUP *group = static_cast<PCB_GROUP*>( item );
497
498 for( EDA_ITEM* grpItem : group->GetItems() )
499 {
500 if( auto grpZone = isSelectedItemAnRA( grpItem ) )
501 refRAs.push_back( grpZone );
502 }
503 }
504 }
505
506 if( refRAs.size() != 1 )
507 {
510 this,
511 _( "Select a reference Rule Area to copy from..." ),
512 [&]( EDA_ITEM* aItem )
513 {
514 return isSelectedItemAnRA( aItem ) != nullptr;
515 }
516 } );
517
518 return 0;
519 }
520
522
523 int status = CheckRACompatibility( refRAs.front() );
524
525 if( status < 0 )
526 return status;
527
528 if( m_areas.m_areas.size() <= 1 )
529 {
530 frame()->ShowInfoBarError( _( "No Rule Areas to repeat layout to have been found." ), true );
531 return 0;
532 }
533
535 int ret = dialog.ShowModal();
536
537 if( ret != wxID_OK )
538 return 0;
539
540 return RepeatLayout( aEvent, refRAs.front() );
541}
542
543
545{
546 m_areas.m_refRA = nullptr;
547
548 for( RULE_AREA& ra : m_areas.m_areas )
549 {
550 if( ra.m_zone == aRefZone )
551 {
552 m_areas.m_refRA = &ra;
553 break;
554 }
555 }
556
557 if( !m_areas.m_refRA )
558 return -1;
559
560 m_areas.m_compatMap.clear();
561
562 for( RULE_AREA& ra : m_areas.m_areas )
563 {
564 if( ra.m_zone == m_areas.m_refRA->m_zone )
565 continue;
566
567 m_areas.m_compatMap[&ra] = RULE_AREA_COMPAT_DATA();
568
569 resolveConnectionTopology( m_areas.m_refRA, &ra, m_areas.m_compatMap[&ra] );
570 }
571
572 return 0;
573}
574
575
576int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, RULE_AREA& aRefArea, RULE_AREA& aTargetArea )
577{
579
580 if( !resolveConnectionTopology( &aRefArea, &aTargetArea, compat ) )
581 {
582 if( Pgm().IsGUI() )
583 {
584 auto errMsg = wxString::Format( _( "Rule Area topologies do not match: %s" ), compat.m_errorMsg );
585 frame()->ShowInfoBarError( errMsg, true );
586 }
587 return -1;
588 }
589
590 BOARD_COMMIT commit( GetManager(), true, false );
591
592 if( !copyRuleAreaContents( &aRefArea, &aTargetArea, &commit, m_areas.m_options, compat ) )
593 {
594 auto errMsg = wxString::Format( _( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
595 m_areas.m_refRA->m_zone->GetZoneName(), aTargetArea.m_zone->GetZoneName() );
596
597 commit.Revert();
598
599 if( Pgm().IsGUI() )
600 {
601 frame()->ShowInfoBarError( errMsg, true );
602 }
603
604 return -1;
605 }
606
608 {
609 if( aTargetArea.m_components.size() == 0 || !( *aTargetArea.m_components.begin() )->GetParentGroup() )
610 {
611 commit.Revert();
612
613 if( Pgm().IsGUI() )
614 {
615 frame()->ShowInfoBarError( _( "Target group does not have a group." ), true );
616 }
617
618 return -1;
619 }
620
621 EDA_GROUP* group = ( *aTargetArea.m_components.begin() )->GetParentGroup();
622
623 commit.Add( group->AsEdaItem() );
624
625 for( BOARD_ITEM* item : compat.m_groupableItems )
626 {
627 commit.Modify( item );
628 group->AddItem( item );
629 }
630 }
631
632 commit.Push( _( "Repeat layout" ) );
633
634 return 0;
635}
636
637
638int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
639{
640 int totalCopied = 0;
641
642 BOARD_COMMIT commit( GetManager(), true, false );
643 for( auto& targetArea : m_areas.m_compatMap )
644 {
645 if( !targetArea.second.m_doCopy )
646 {
647 wxLogTrace( traceMultichannelTool, wxT( "skipping copy to RA '%s' (disabled in dialog)\n" ),
648 targetArea.first->m_ruleName );
649 continue;
650 }
651
652 if( !targetArea.second.m_isOk )
653 continue;
654
655 if( !copyRuleAreaContents( m_areas.m_refRA, targetArea.first, &commit, m_areas.m_options, targetArea.second ) )
656 {
657 auto errMsg = wxString::Format(
658 _( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
659 m_areas.m_refRA->m_zone->GetZoneName(),
660 targetArea.first->m_zone->GetZoneName() );
661
662 commit.Revert();
663
664 if( Pgm().IsGUI() )
665 frame()->ShowInfoBarError( errMsg, true );
666
667 return -1;
668 }
669 totalCopied++;
670 wxSafeYield();
671 }
672
673 if( m_areas.m_options.m_groupItems )
674 {
675 for( const auto& [targetArea, compatData] : m_areas.m_compatMap )
676 {
677 pruneExistingGroups( commit, compatData.m_affectedItems );
678
679 PCB_GROUP* group = new PCB_GROUP( board() );
680
681 commit.Add( group );
682
683 for( BOARD_ITEM* item : compatData.m_groupableItems )
684 {
685 commit.Modify( item );
686 group->AddItem( item );
687 }
688 }
689 }
690
691 commit.Push( _( "Repeat layout" ) );
692
693 if( Pgm().IsGUI() )
694 frame()->ShowInfoBarMsg( wxString::Format( _( "Copied to %d Rule Areas." ), totalCopied ), true );
695
696 return 0;
697}
698
699
700wxString MULTICHANNEL_TOOL::stripComponentIndex( const wxString& aRef ) const
701{
702 wxString rv;
703
704 // fixme: i'm pretty sure this can be written in a simpler way, but I really suck at figuring
705 // out which wx's built in functions would do it for me. And I hate regexps :-)
706 for( auto k : aRef )
707 {
708 if( !k.IsAscii() )
709 break;
710
711 char c;
712 k.GetAsChar( &c );
713
714 if( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c == '_' ) )
715 rv.Append( k );
716 else
717 break;
718 }
719
720 return rv;
721}
722
723
724int MULTICHANNEL_TOOL::findRoutingInRuleArea( RULE_AREA* aRuleArea, std::set<BOARD_CONNECTED_ITEM*>& aOutput,
725 std::shared_ptr<CONNECTIVITY_DATA> aConnectivity,
726 const SHAPE_POLY_SET& aRAPoly, const REPEAT_LAYOUT_OPTIONS& aOpts ) const
727{
728 if( !aRuleArea || !aRuleArea->m_zone )
729 return 0;
730
731 // The user also will consider tracks and vias that are inside the source area but
732 // not connected to any of the source pads to count as "routing" (e.g. stitching vias)
733
734 int count = 0;
735
736 // When we're copying the layout of a design block, we are provided an exact list of items
737 // rather than querying the board for items that are inside the area.
739 {
740 // Get all board connected items that are from the design block, except pads,
741 // which shouldn't be copied
742 for( EDA_ITEM* item : aRuleArea->m_designBlockItems )
743 {
744 // Include any connected items except pads.
745 if( item->Type() == PCB_PAD_T )
746 continue;
747
748 if( BOARD_CONNECTED_ITEM* bci = dynamic_cast<BOARD_CONNECTED_ITEM*>( item ) )
749 aOutput.insert( bci );
750 }
751
752 return (int) aOutput.size();
753 }
754
756 PCBEXPR_UCODE ucode;
757 PCBEXPR_CONTEXT ctx, preflightCtx;
758
759 auto reportError = [&]( const wxString& aMessage, int aOffset )
760 {
761 wxLogTrace( traceMultichannelTool, wxT( "ERROR: %s" ), aMessage );
762 };
763
764 ctx.SetErrorCallback( reportError );
765 preflightCtx.SetErrorCallback( reportError );
766 compiler.SetErrorCallback( reportError );
767
768 bool restoreBlankName = false;
769
770 if( aRuleArea->m_zone->GetZoneName().IsEmpty() )
771 {
772 restoreBlankName = true;
773 aRuleArea->m_zone->SetZoneName( aRuleArea->m_zone->m_Uuid.AsString() );
774 }
775
776 wxString ruleText = wxString::Format( wxT( "A.enclosedByArea('%s')" ), aRuleArea->m_zone->GetZoneName() );
777
778 auto testAndAdd =
779 [&]( BOARD_CONNECTED_ITEM* aItem )
780 {
781 if( aOutput.contains( aItem ) )
782 return;
783
784 ctx.SetItems( aItem, aItem );
785 LIBEVAL::VALUE* val = ucode.Run( &ctx );
786
787 if( val->AsDouble() != 0.0 )
788 {
789 aOutput.insert( aItem );
790 count++;
791 }
792 };
793
794 if( compiler.Compile( ruleText, &ucode, &preflightCtx ) )
795 {
796 for( PCB_TRACK* track : board()->Tracks() )
797 testAndAdd( track );
798 }
799
800 if( restoreBlankName )
801 aRuleArea->m_zone->SetZoneName( wxEmptyString );
802
803 return count;
804}
805
806
808 BOARD_COMMIT* aCommit, REPEAT_LAYOUT_OPTIONS aOpts,
809 RULE_AREA_COMPAT_DATA& aCompatData )
810{
811 // copy RA shapes first
812 SHAPE_LINE_CHAIN refOutline = aRefArea->m_zone->Outline()->COutline( 0 );
813 SHAPE_LINE_CHAIN targetOutline = aTargetArea->m_zone->Outline()->COutline( 0 );
814
815 FOOTPRINT* targetAnchorFp = nullptr;
816 VECTOR2I disp = aTargetArea->m_center - aRefArea->m_center;
817 EDA_ANGLE rot = EDA_ANGLE( 0 );
818
819 if( aOpts.m_anchorFp )
820 {
821 for( auto& fpPair : aCompatData.m_matchingComponents )
822 {
823 if( fpPair.first->GetReference() == aOpts.m_anchorFp->GetReference() )
824 targetAnchorFp = fpPair.second;
825 }
826
827 if( targetAnchorFp )
828 {
829 VECTOR2I oldpos = aOpts.m_anchorFp->GetPosition();
830 rot = EDA_ANGLE( targetAnchorFp->GetOrientationDegrees() - aOpts.m_anchorFp->GetOrientationDegrees() );
831 aOpts.m_anchorFp->Rotate( VECTOR2( 0, 0 ), EDA_ANGLE( rot ) );
832 oldpos = aOpts.m_anchorFp->GetPosition();
833 VECTOR2I newpos = targetAnchorFp->GetPosition();
834 disp = newpos - oldpos;
835 aOpts.m_anchorFp->Rotate( VECTOR2( 0, 0 ), EDA_ANGLE( -rot ) );
836 }
837 }
838
839 SHAPE_POLY_SET refPoly;
840 refPoly.AddOutline( refOutline );
841 refPoly.CacheTriangulation( false );
842
843 SHAPE_POLY_SET targetPoly;
844
845 SHAPE_LINE_CHAIN newTargetOutline( refOutline );
846 newTargetOutline.Rotate( rot, VECTOR2( 0, 0 ) );
847 newTargetOutline.Move( disp );
848 targetPoly.AddOutline( newTargetOutline );
849 targetPoly.CacheTriangulation( false );
850
851 auto connectivity = board()->GetConnectivity();
852
853 // Only stage changes for a target Rule Area zone if it actually belongs to the board.
854 // In some workflows (e.g. ApplyDesignBlockLayout), the target area is a temporary zone
855 // and is not added to the BOARD.
856 bool targetZoneOnBoard = false;
857
858 if( aTargetArea->m_zone )
859 {
860 for( ZONE* z : board()->Zones() )
861 {
862 if( z == aTargetArea->m_zone )
863 {
864 targetZoneOnBoard = true;
865 break;
866 }
867 }
868 }
869
870 if( targetZoneOnBoard )
871 {
872 aCommit->Modify( aTargetArea->m_zone );
873 aCompatData.m_affectedItems.insert( aTargetArea->m_zone );
874 aCompatData.m_groupableItems.insert( aTargetArea->m_zone );
875 }
876
877 if( aOpts.m_copyRouting )
878 {
879 std::set<BOARD_CONNECTED_ITEM*> refRouting;
880 std::set<BOARD_CONNECTED_ITEM*> targetRouting;
881
882 wxLogTrace( traceMultichannelTool, wxT( "copying routing: %d fps\n" ),
883 (int) aCompatData.m_matchingComponents.size() );
884
885 std::set<int> refc;
886 std::set<int> targc;
887
888 for( auto& fpPair : aCompatData.m_matchingComponents )
889 {
890 for( PAD* pad : fpPair.first->Pads() )
891 refc.insert( pad->GetNetCode() );
892
893 for( PAD* pad : fpPair.second->Pads() )
894 targc.insert( pad->GetNetCode() );
895 }
896
897 findRoutingInRuleArea( aTargetArea, targetRouting, connectivity, targetPoly, aOpts );
898 findRoutingInRuleArea( aRefArea, refRouting, connectivity, refPoly, aOpts );
899
900 for( BOARD_CONNECTED_ITEM* item : targetRouting )
901 {
902 // Never remove pads as part of routing copy.
903 if( item->Type() == PCB_PAD_T )
904 continue;
905 if( item->IsLocked() && !aOpts.m_includeLockedItems )
906 continue;
907 if( aOpts.m_connectedRoutingOnly && !targc.contains( item->GetNetCode() ) )
908 continue;
909 // item already removed
910 if( aCommit->GetStatus( item ) != 0 )
911 continue;
912
913 if( aTargetArea->m_zone->GetLayerSet().Contains( item->GetLayer() ) )
914 {
915 aCompatData.m_affectedItems.insert( item );
916 aCommit->Remove( item );
917 }
918 }
919
920 for( BOARD_CONNECTED_ITEM* item : refRouting )
921 {
922 // Never copy pads as part of routing copy.
923 if( item->Type() == PCB_PAD_T )
924 continue;
925 if( item->IsLocked() && !aOpts.m_includeLockedItems )
926 continue;
927 if( aOpts.m_connectedRoutingOnly && !refc.contains( item->GetNetCode() ) )
928 continue;
929 if( !aRefArea->m_zone->GetLayerSet().Contains( item->GetLayer() ) )
930 continue;
931
932 if( !aTargetArea->m_zone->GetLayerSet().Contains( item->GetLayer() ) )
933 continue;
934
935 BOARD_CONNECTED_ITEM* copied = static_cast<BOARD_CONNECTED_ITEM*>( item->Clone() );
936
937 fixupNet( item, copied, aCompatData.m_matchingComponents );
938
939 copied->Rotate( VECTOR2( 0, 0 ), rot );
940 copied->Move( disp );
941 copied->SetParentGroup( nullptr );
942 const_cast<KIID&>( copied->m_Uuid ) = KIID();
943 aCompatData.m_groupableItems.insert( copied );
944 aCommit->Add( copied );
945 }
946 }
947
948 if( aOpts.m_copyOtherItems )
949 {
950 std::set<BOARD_ITEM*> sourceItems;
951 std::set<BOARD_ITEM*> targetItems;
952
953 findOtherItemsInRuleArea( aRefArea, sourceItems );
954 findOtherItemsInRuleArea( aTargetArea, targetItems );
955
956 for( BOARD_ITEM* item : targetItems )
957 {
958 if( item->Type() == PCB_TEXT_T && item->GetParent() && item->GetParent()->Type() == PCB_FOOTPRINT_T )
959 continue;
960
961 if( item->IsLocked() && !aOpts.m_includeLockedItems )
962 continue;
963
964 // item already removed
965 if( aCommit->GetStatus( item ) != 0 )
966 continue;
967
968 if( item->Type() != PCB_ZONE_T )
969 {
970 if( aTargetArea->m_zone->GetLayerSet().Contains( item->GetLayer() ) )
971 {
972 aCompatData.m_affectedItems.insert( item );
973 aCommit->Remove( item );
974 }
975 }
976 else
977 {
978 ZONE* zone = static_cast<ZONE*>( item );
979
980 // Check all zone layers are included in the rule area
981 bool layerMismatch = false;
982 LSET zoneLayers = zone->GetLayerSet();
983
984 for( const PCB_LAYER_ID& layer : zoneLayers )
985 {
986 if( !aTargetArea->m_zone->GetLayerSet().Contains( layer ) )
987 layerMismatch = true;
988 }
989
990 if( !layerMismatch )
991 {
992 aCompatData.m_affectedItems.insert( zone );
993 aCommit->Remove( zone );
994 }
995 }
996 }
997
998 for( BOARD_ITEM* item : sourceItems )
999 {
1000 if( item->Type() == PCB_TEXT_T && item->GetParent() && item->GetParent()->Type() == PCB_FOOTPRINT_T )
1001 continue;
1002
1003 if( item->IsLocked() && !aOpts.m_includeLockedItems )
1004 continue;
1005
1006 BOARD_ITEM* copied = nullptr;
1007
1008 if( item->Type() != PCB_ZONE_T )
1009 {
1010 if( !aRefArea->m_zone->GetLayerSet().Contains( item->GetLayer() ) )
1011 continue;
1012 if( !aTargetArea->m_zone->GetLayerSet().Contains( item->GetLayer() ) )
1013 continue;
1014
1015 if( item->Type() == PCB_GROUP_T )
1016 copied = static_cast<PCB_GROUP*>( item )->DeepClone();
1017 else
1018 copied = static_cast<BOARD_ITEM*>( item->Clone() );
1019 }
1020 else
1021 {
1022 ZONE* zone = static_cast<ZONE*>( item );
1023
1024 // Check all zone layers are included in the rule area
1025 bool layerMismatch = false;
1026 LSET zoneLayers = zone->GetLayerSet();
1027
1028 for( const PCB_LAYER_ID& layer : zoneLayers )
1029 {
1030 if( !aRefArea->m_zone->GetLayerSet().Contains( layer )
1031 || !aTargetArea->m_zone->GetLayerSet().Contains( layer ) )
1032 {
1033 layerMismatch = true;
1034 }
1035 }
1036
1037 if( layerMismatch )
1038 continue;
1039
1040 ZONE* targetZone = static_cast<ZONE*>( item->Clone() );
1041 fixupNet( zone, targetZone, aCompatData.m_matchingComponents );
1042
1043 copied = targetZone;
1044 }
1045
1046 if( copied )
1047 {
1048 copied->ClearFlags();
1049 copied->SetParentGroup( nullptr );
1050 const_cast<KIID&>( copied->m_Uuid ) = KIID();
1051 copied->Rotate( VECTOR2( 0, 0 ), rot );
1052 copied->Move( disp );
1053 aCompatData.m_groupableItems.insert( copied );
1054 aCommit->Add( copied );
1055 }
1056 }
1057 }
1058
1059 if( aOpts.m_copyPlacement )
1060 {
1061 for( auto& fpPair : aCompatData.m_matchingComponents )
1062 {
1063 FOOTPRINT* refFP = fpPair.first;
1064 FOOTPRINT* targetFP = fpPair.second;
1065
1066 if( !aRefArea->m_zone->GetLayerSet().Contains( refFP->GetLayer() ) )
1067 {
1068 wxLogTrace( traceMultichannelTool, wxT( "discard ref:%s (ref layer)\n" ),
1069 refFP->GetReference() );
1070 continue;
1071 }
1072 if( !aTargetArea->m_zone->GetLayerSet().Contains( refFP->GetLayer() ) )
1073 {
1074 wxLogTrace( traceMultichannelTool, wxT( "discard ref:%s (target layer)\n" ),
1075 refFP->GetReference() );
1076 continue;
1077 }
1078
1079 // Ignore footprints outside of the rule area
1080 if( !refFP->GetEffectiveShape( refFP->GetLayer() )->Collide( &refPoly, 0 ) )
1081 continue;
1082
1083 if( targetFP->IsLocked() && !aOpts.m_includeLockedItems )
1084 continue;
1085
1086 aCommit->Modify( targetFP );
1087
1088 targetFP->SetLayerAndFlip( refFP->GetLayer() );
1089 targetFP->SetOrientation( refFP->GetOrientation() );
1090 targetFP->SetPosition( refFP->GetPosition() );
1091 targetFP->Rotate( VECTOR2( 0, 0 ), rot );
1092 targetFP->Move( disp );
1093 for( PCB_FIELD* refField : refFP->GetFields() )
1094 {
1095 if( !refField->IsVisible() )
1096 continue;
1097
1098 PCB_FIELD* targetField = targetFP->GetField( refField->GetName() );
1099 wxCHECK2( targetField, continue );
1100
1101 targetField->SetAttributes( refField->GetAttributes() );
1102 targetField->SetPosition( refField->GetPosition() );
1103 targetField->Rotate( VECTOR2( 0, 0 ), rot );
1104 targetField->Move( disp );
1105 targetField->SetIsKnockout( refField->IsKnockout() );
1106 }
1107
1108 aCompatData.m_affectedItems.insert( targetFP );
1109 aCompatData.m_groupableItems.insert( targetFP );
1110 }
1111 }
1112
1113 aTargetArea->m_zone->RemoveAllContours();
1114 aTargetArea->m_zone->AddPolygon( newTargetOutline );
1115 aTargetArea->m_zone->UnHatchBorder();
1116 aTargetArea->m_zone->HatchBorder();
1117
1118 return true;
1119}
1120
1126 TMATCH::COMPONENT_MATCHES& aComponentMatches )
1127{
1128 auto connectivity = board()->GetConnectivity();
1129 const std::vector<BOARD_CONNECTED_ITEM*> refConnectedPads = connectivity->GetNetItems( aRef->GetNetCode(),
1130 { PCB_PAD_T } );
1131
1132 for( const BOARD_CONNECTED_ITEM* refConItem : refConnectedPads )
1133 {
1134 if( refConItem->Type() != PCB_PAD_T )
1135 continue;
1136
1137 const PAD* refPad = static_cast<const PAD*>( refConItem );
1138 FOOTPRINT* sourceFootprint = refPad->GetParentFootprint();
1139
1140 if( aComponentMatches.contains( sourceFootprint ) )
1141 {
1142 const FOOTPRINT* targetFootprint = aComponentMatches[sourceFootprint];
1143 std::vector<const PAD*> targetFpPads = targetFootprint->GetPads( refPad->GetNumber() );
1144
1145 if( !targetFpPads.empty() )
1146 {
1147 int targetNetCode = targetFpPads[0]->GetNet()->GetNetCode();
1148 aTarget->SetNetCode( targetNetCode );
1149
1150 break;
1151 }
1152 }
1153 }
1154}
1155
1156
1158 RULE_AREA_COMPAT_DATA& aMatches )
1159{
1160 using namespace TMATCH;
1161
1162 std::unique_ptr<CONNECTION_GRAPH> cgRef ( CONNECTION_GRAPH::BuildFromFootprintSet( aRefArea->m_components ) );
1163 std::unique_ptr<CONNECTION_GRAPH> cgTarget ( CONNECTION_GRAPH::BuildFromFootprintSet( aTargetArea->m_components ) );
1164
1165 auto status = cgRef->FindIsomorphism( cgTarget.get(), aMatches.m_matchingComponents );
1166
1167 switch( status )
1168 {
1170 aMatches.m_isOk = true;
1171 aMatches.m_errorMsg = _( "OK" );
1172 break;
1174 aMatches.m_isOk = false;
1175 aMatches.m_errorMsg = _( "One or both of the areas has no components assigned." );
1176 break;
1178 aMatches.m_isOk = false;
1179 aMatches.m_errorMsg = _( "Component count mismatch" );
1180 break;
1182 aMatches.m_isOk = false;
1183 aMatches.m_errorMsg = _( "Iteration count exceeded (timeout)" );
1184 break;
1186 aMatches.m_isOk = false;
1187 aMatches.m_errorMsg = _( "Topology mismatch" );
1188 break;
1189 default:
1190 break;
1191 }
1192
1193 return ( status == TMATCH::CONNECTION_GRAPH::ST_OK );
1194}
1195
1196
1198 const std::unordered_set<BOARD_ITEM*>& aItemsToRemove )
1199{
1200 // Note: groups are only collections, not "real" hierarchy. A group's members are still parented
1201 // by the board (and therefore nested groups are still in the board's list of groups).
1202 for( PCB_GROUP* group : board()->Groups() )
1203 {
1204 std::vector<EDA_ITEM*> pruneList;
1205
1206 for( EDA_ITEM* refItem : group->GetItems() )
1207 {
1208 for( BOARD_ITEM* testItem : aItemsToRemove )
1209 {
1210 if( refItem->m_Uuid == testItem->m_Uuid )
1211 pruneList.push_back( refItem );
1212 }
1213 }
1214
1215 if( !pruneList.empty() )
1216 {
1217 aCommit.Modify( group );
1218
1219 for( EDA_ITEM* item : pruneList )
1220 group->RemoveItem( item );
1221
1222 if( group->GetItems().empty() )
1223 aCommit.Remove( group );
1224 }
1225 }
1226
1227 return false;
1228}
1229
1230
1232{
1233 if( Pgm().IsGUI() )
1234 {
1236
1237 if( m_areas.m_areas.size() <= 1 )
1238 {
1239 frame()->ShowInfoBarError( _( "Cannot auto-generate any placement areas because the "
1240 "schematic has only one or no hierarchical sheets, "
1241 "groups, or component classes." ),
1242 true );
1243 return 0;
1244 }
1245
1247 int ret = dialog.ShowModal();
1248
1249 if( ret != wxID_OK )
1250 return 0;
1251 }
1252
1253 for( ZONE* zone : board()->Zones() )
1254 {
1255 if( !zone->GetIsRuleArea() )
1256 continue;
1257
1258 if( !zone->GetPlacementAreaEnabled() )
1259 continue;
1260
1261 std::set<FOOTPRINT*> components;
1262 RULE_AREA zoneRA;
1263 zoneRA.m_zone = zone;
1264 zoneRA.m_sourceType = zone->GetPlacementAreaSourceType();
1265 findComponentsInRuleArea( &zoneRA, components );
1266
1267 if( components.empty() )
1268 continue;
1269
1270 for( RULE_AREA& ra : m_areas.m_areas )
1271 {
1272 if( components == ra.m_components )
1273 {
1274 if( zone->GetPlacementAreaSourceType() == PLACEMENT_SOURCE_T::SHEETNAME )
1275 {
1276 wxLogTrace( traceMultichannelTool,
1277 wxT( "Placement rule area for sheet '%s' already exists as '%s'\n" ),
1278 ra.m_sheetPath, zone->GetZoneName() );
1279 }
1280 else if( zone->GetPlacementAreaSourceType() == PLACEMENT_SOURCE_T::COMPONENT_CLASS )
1281 {
1282 wxLogTrace( traceMultichannelTool,
1283 wxT( "Placement rule area for component class '%s' already exists as '%s'\n" ),
1284 ra.m_componentClass, zone->GetZoneName() );
1285 }
1286 else
1287 {
1288 wxLogTrace( traceMultichannelTool,
1289 wxT( "Placement rule area for group '%s' already exists as '%s'\n" ),
1290 ra.m_groupName, zone->GetZoneName() );
1291 }
1292
1293 ra.m_oldZone = zone;
1294 ra.m_existsAlready = true;
1295 }
1296 }
1297 }
1298
1299 wxLogTrace( traceMultichannelTool, wxT( "%d placement areas found\n" ), (int) m_areas.m_areas.size() );
1300
1301 BOARD_COMMIT commit( GetManager(), true, false );
1302
1303 for( RULE_AREA& ra : m_areas.m_areas )
1304 {
1305 if( !ra.m_generateEnabled )
1306 continue;
1307
1308 if( ra.m_existsAlready && !m_areas.m_replaceExisting )
1309 continue;
1310
1311 if( ra.m_components.empty() )
1312 continue;
1313
1314 SHAPE_LINE_CHAIN raOutline = buildRAOutline( ra.m_components, 100000 );
1315
1316 std::unique_ptr<ZONE> newZone( new ZONE( board() ) );
1317
1319 newZone->SetZoneName( wxString::Format( wxT( "auto-placement-area-%s" ), ra.m_sheetPath ) );
1321 newZone->SetZoneName( wxString::Format( wxT( "auto-placement-area-%s" ), ra.m_componentClass ) );
1322 else
1323 newZone->SetZoneName( wxString::Format( wxT( "auto-placement-area-%s" ), ra.m_groupName ) );
1324
1325 wxLogTrace( traceMultichannelTool, wxT( "Generated rule area '%s' (%d components)\n" ),
1326 newZone->GetZoneName(),
1327 (int) ra.m_components.size() );
1328
1329 newZone->SetIsRuleArea( true );
1330 newZone->SetLayerSet( LSET::AllCuMask() );
1331 newZone->SetPlacementAreaEnabled( true );
1332 newZone->SetDoNotAllowZoneFills( false );
1333 newZone->SetDoNotAllowVias( false );
1334 newZone->SetDoNotAllowTracks( false );
1335 newZone->SetDoNotAllowPads( false );
1336 newZone->SetDoNotAllowFootprints( false );
1337
1339 {
1340 newZone->SetPlacementAreaSourceType( PLACEMENT_SOURCE_T::SHEETNAME );
1341 newZone->SetPlacementAreaSource( ra.m_sheetPath );
1342 }
1344 {
1345 newZone->SetPlacementAreaSourceType( PLACEMENT_SOURCE_T::COMPONENT_CLASS );
1346 newZone->SetPlacementAreaSource( ra.m_componentClass );
1347 }
1348 else
1349 {
1350 newZone->SetPlacementAreaSourceType( PLACEMENT_SOURCE_T::GROUP_PLACEMENT );
1351 newZone->SetPlacementAreaSource( ra.m_groupName );
1352 }
1353
1354 newZone->AddPolygon( raOutline );
1355 newZone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH );
1356
1357 if( ra.m_existsAlready )
1358 {
1359 commit.Remove( ra.m_oldZone );
1360 }
1361
1362 ra.m_zone = newZone.release();
1363 commit.Add( ra.m_zone );
1364 }
1365
1366 // fixme: handle corner cases where the items belonging to a Rule Area already
1367 // belong to other groups.
1368
1369 if( m_areas.m_options.m_groupItems )
1370 {
1371 for( RULE_AREA& ra : m_areas.m_areas )
1372 {
1373 if( !ra.m_generateEnabled )
1374 continue;
1375
1376 if( ra.m_existsAlready && !m_areas.m_replaceExisting )
1377 continue;
1378
1379 std::unordered_set<BOARD_ITEM*> toPrune;
1380
1381 std::copy( ra.m_components.begin(), ra.m_components.end(), std::inserter( toPrune, toPrune.begin() ) );
1382
1383 if( ra.m_existsAlready )
1384 toPrune.insert( ra.m_zone );
1385
1386 pruneExistingGroups( commit, toPrune );
1387
1388 PCB_GROUP* group = new PCB_GROUP( board() );
1389
1390 commit.Add( group );
1391
1392 commit.Modify( ra.m_zone );
1393 group->AddItem( ra.m_zone );
1394
1395 for( FOOTPRINT* fp : ra.m_components )
1396 {
1397 commit.Modify( fp );
1398 group->AddItem( fp );
1399 }
1400 }
1401 }
1402
1403 commit.Push( _( "Auto-generate placement rule areas" ) );
1404
1405 return true;
1406}
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
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:79
virtual void SetIsKnockout(bool aKnockout)
Definition board_item.h:320
FOOTPRINT * GetParentFootprint() const
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition board.h:521
Represent a set of changes (additions, deletions or modifications) of a data model (e....
Definition commit.h:72
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
Definition commit.h:90
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:106
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
Definition commit.h:78
int GetStatus(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Returns status of an item.
Definition commit.cpp:167
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.
const std::vector< BOARD_CONNECTED_ITEM * > GetNetItems(int aNetCode, const std::vector< KICAD_T > &aTypes) const
Function GetNetItems() Returns the list of items that belong to a certain net.
int ShowModal() override
A set of EDA_ITEMs (i.e., without duplicates).
Definition eda_group.h:46
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
const KIID m_Uuid
Definition eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual bool IsType(const std::vector< KICAD_T > &aScanTypes) const
Check whether the item is one of the listed types.
Definition eda_item.h:192
void SetAttributes(const EDA_TEXT &aSrc, bool aSetPosition=true)
Set the text attributes from another instance.
Definition eda_text.cpp:434
void SetPosition(const VECTOR2I &aPos) override
EDA_ANGLE GetOrientation() const
Definition footprint.h:248
void SetOrientation(const EDA_ANGLE &aNewAngle)
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.
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
PCB_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this footprint.
double GetOrientationDegrees() const
Definition footprint.h:264
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition footprint.h:257
bool IsLocked() const override
Definition footprint.h:454
void SetLayerAndFlip(PCB_LAYER_ID aLayer)
Used as Layer property setter – performs a flip if necessary to set the footprint layer.
void Move(const VECTOR2I &aMoveVector) override
Move this object.
std::vector< const PAD * > GetPads(const wxString &aPadNumber, const PAD *aIgnore=nullptr) const
void GetFields(std::vector< PCB_FIELD * > &aVector, bool aVisibleOnly) const
Populate a std::vector with PCB_TEXTs.
const wxString & GetReference() const
Definition footprint.h:661
VECTOR2I GetPosition() const override
Definition footprint.h:245
bool IsBOARD_ITEM() const
Definition view_item.h:102
Definition kiid.h:49
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)
virtual double AsDouble() const
LSET is a set of PCB_LAYER_IDs.
Definition lset.h:37
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:582
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
bool findOtherItemsInRuleArea(RULE_AREA *aRuleArea, std::set< BOARD_ITEM * > &aItems)
int repeatLayout(const TOOL_EVENT &aEvent)
bool findComponentsInRuleArea(RULE_AREA *aRuleArea, std::set< FOOTPRINT * > &aComponents)
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)
int findRoutingInRuleArea(RULE_AREA *aRuleArea, std::set< BOARD_CONNECTED_ITEM * > &aOutput, std::shared_ptr< CONNECTIVITY_DATA > aConnectivity, const SHAPE_POLY_SET &aRAPoly, const REPEAT_LAYOUT_OPTIONS &aOpts) const
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)
void fixupNet(BOARD_CONNECTED_ITEM *aRef, BOARD_CONNECTED_ITEM *aTarget, TMATCH::COMPONENT_MATCHES &aComponentMatches)
Attempts to make sure copied items are assigned the right net.
bool copyRuleAreaContents(RULE_AREA *aRefArea, RULE_AREA *aTargetArea, BOARD_COMMIT *aCommit, REPEAT_LAYOUT_OPTIONS aOpts, RULE_AREA_COMPAT_DATA &aCompatData)
std::set< FOOTPRINT * > queryComponentsInComponentClass(const wxString &aComponentClassName) const
RULE_AREA * findRAByName(const wxString &aName)
std::set< FOOTPRINT * > queryComponentsInGroup(const wxString &aGroupName) const
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
static TOOL_ACTION generatePlacementRuleAreas
static TOOL_ACTION selectItemInteractively
Selection of reference points/items.
A set of BOARD_ITEMs (i.e., without duplicates).
Definition pcb_group.h:53
virtual void SetPosition(const VECTOR2I &aPos) override
Definition pcb_text.h:89
void Move(const VECTOR2I &aMoveVector) override
Move this object.
Definition pcb_text.h:94
void Rotate(const VECTOR2I &aRotCentre, const EDA_ANGLE &aAngle) override
Rotate this object.
Definition pcb_text.cpp:399
T * frame() const
PCB_TOOL_BASE(TOOL_ID aId, const std::string &aName)
Constructor.
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
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
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
virtual bool Collide(const VECTOR2I &aP, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const
Check if the boundary of shape (this) lies closer to the point aP than aClearance,...
Definition shape.h:181
static std::unique_ptr< CONNECTION_GRAPH > BuildFromFootprintSet(const std::set< FOOTPRINT * > &aFps)
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:171
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).
Define a general 2D-vector/point.
Definition vector2d.h:71
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:704
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1117
wxString GetPlacementAreaSource() const
Definition zone.h:709
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition zone.cpp:1244
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
Definition zone.h:711
SHAPE_POLY_SET * Outline()
Definition zone.h:335
const wxString & GetZoneName() const
Definition zone.h:163
bool GetPlacementAreaEnabled() const
Definition zone.h:706
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:136
void SetZoneName(const wxString &aName)
Definition zone.h:164
void UnHatchBorder()
Clear the zone's hatch.
Definition zone.cpp:1238
void RemoveAllContours(void)
Definition zone.h:554
void BuildConvexHull(std::vector< VECTOR2I > &aResult, const std::vector< VECTOR2I > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
#define _(s)
@ RECURSE
Definition eda_item.h:51
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.
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:913
see class PGM_BASE
Utility functions for working with shapes.
std::unordered_set< BOARD_ITEM * > m_affectedItems
Filled in by copyRuleAreaContents with items that were affected by the copy operation.
TMATCH::COMPONENT_MATCHES m_matchingComponents
std::unordered_set< BOARD_ITEM * > m_groupableItems
Filled in by copyRuleAreaContents with affected items that can be grouped together.
VECTOR2I m_center
std::unordered_set< EDA_ITEM * > m_designBlockItems
wxString m_sheetName
PLACEMENT_SOURCE_T m_sourceType
wxString m_componentClass
std::set< FOOTPRINT * > m_components
wxString m_ruleName
wxString m_groupName
wxString m_sheetPath
bool copied
wxString result
Test unit parsing edge cases and error handling.
@ 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
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695