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 (C) Kicad Developers, see change_log.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>
37#include <pcb_group.h>
40#include <optional>
41#include <algorithm>
42#include <random>
43#include <core/profile.h>
44#include <wx/log.h>
45#include <pgm_base.h>
46
47
48#define MULTICHANNEL_EXTRA_DEBUG
49
50static const wxString traceMultichannelTool = wxT( "MULTICHANNEL_TOOL" );
51
52
54{
55}
56
57
59{
60
61}
62
63
65{
68}
69
70
72 std::set<FOOTPRINT*>& aComponents )
73{
75 PCBEXPR_UCODE ucode;
76 PCBEXPR_CONTEXT ctx, preflightCtx;
77
78 auto reportError = [&]( const wxString& aMessage, int aOffset )
79 {
80 wxLogTrace( traceMultichannelTool, wxT( "ERROR: %s"), aMessage );
81 };
82
83 ctx.SetErrorCallback( reportError );
84 preflightCtx.SetErrorCallback( reportError );
85 compiler.SetErrorCallback( reportError );
86 //compiler.SetDebugReporter( m_reporter );
87
88 wxLogTrace( traceMultichannelTool, wxT( "rule area '%s'"), aRuleArea->GetZoneName() );
89
90 auto ok = compiler.Compile( aRuleArea->GetRuleAreaExpression(), &ucode, &preflightCtx );
91
92 if( !ok )
93 {
94 return false;
95 }
96
97 for( FOOTPRINT* fp : board()->Footprints() )
98 {
99 ctx.SetItems( fp, fp );
100 auto val = ucode.Run( &ctx );
101 if( val->AsDouble() != 0.0 )
102 {
103 wxLogTrace( traceMultichannelTool, wxT( " - %s [sheet %s]" ), fp->GetReference(),
104 fp->GetSheetname() );
105
106 aComponents.insert( fp );
107 }
108 }
109
110 return true;
111}
112
113
114std::set<FOOTPRINT*> MULTICHANNEL_TOOL::queryComponentsInSheet( wxString aSheetName )
115{
116 std::set<FOOTPRINT*> rv;
117 if( aSheetName.EndsWith( wxT( "/" ) ) )
118 aSheetName.RemoveLast();
119
120 for( auto& fp : board()->Footprints() )
121 {
122 auto sn = fp->GetSheetname();
123 if( sn.EndsWith( wxT( "/" ) ) )
124 sn.RemoveLast();
125
126 if( sn == aSheetName )
127 {
128 rv.insert( fp );
129 }
130 }
131
132 return rv;
133}
134
135
136const SHAPE_LINE_CHAIN MULTICHANNEL_TOOL::buildRAOutline( std::set<FOOTPRINT*>& aFootprints,
137 int aMargin )
138{
139 std::vector<VECTOR2I> bbCorners, hullVertices;
140
141 for( auto fp : aFootprints )
142 {
143 auto bb = fp->GetBoundingBox( false, false );
144 bb.Inflate( aMargin );
145
146 bbCorners.push_back( VECTOR2I( bb.GetX(), bb.GetY() ) );
147 bbCorners.push_back( VECTOR2I( bb.GetX() + bb.GetWidth(), bb.GetY() ) );
148 bbCorners.push_back( VECTOR2I( bb.GetX() + bb.GetWidth(), bb.GetY() + bb.GetHeight() ) );
149 bbCorners.push_back( VECTOR2I( bb.GetX(), bb.GetY() + bb.GetHeight() ) );
150 }
151
152 BuildConvexHull( hullVertices, bbCorners );
153
154 SHAPE_LINE_CHAIN hull( hullVertices );
155 SHAPE_LINE_CHAIN raOutline;
156
157 // make the newly computed convex hull use only 90 degree segments
158 hull.SetClosed( true );
159 for( int i = 0; i < hull.SegmentCount(); i++ )
160 {
161 const auto& seg = hull.CSegment( i );
162 const VECTOR2I p0( seg.A.x, seg.B.y );
163 const VECTOR2I p1( seg.B.x, seg.A.y );
164
165 raOutline.Append( seg.A );
166 if( hull.PointInside( p0 ) )
167 raOutline.Append( p0 );
168 else
169 raOutline.Append( p1 );
170 }
171
172 raOutline.SetClosed( true );
173 raOutline.Simplify();
174
175 return raOutline;
176}
177
178
180{
181 using PathAndName = std::pair<wxString, wxString>;
182 std::set<PathAndName> uniqueSheets;
183
184 m_areas.m_areas.clear();
185
186 for( FOOTPRINT* fp : board()->Footprints() )
187 {
188 uniqueSheets.insert( PathAndName( fp->GetSheetname(), fp->GetSheetfile() ) );
189 }
190
191 for( const PathAndName& sheet : uniqueSheets )
192 {
193 RULE_AREA ent;
194
195 ent.m_generateEnabled = false;
196 ent.m_sheetPath = sheet.first;
197 ent.m_sheetName = sheet.second;
199 m_areas.m_areas.push_back( ent );
200
201 wxLogTrace( traceMultichannelTool, wxT("found sheet '%s' @ '%s' s %d\n"),
202 ent.m_sheetName, ent.m_sheetPath, (int)m_areas.m_areas.size() );
203 }
204}
205
206
208{
209 m_areas.m_areas.clear();
210
211 for( ZONE* zone : board()->Zones() )
212 {
213 if( !zone->GetIsRuleArea() )
214 continue;
215 if( zone->GetRuleAreaType() != RULE_AREA_TYPE::PLACEMENT )
216 continue;
217
218 RULE_AREA area;
219
220 area.m_existsAlready = true;
221 area.m_area = zone;
222
224
225 area.m_ruleName = zone->GetZoneName();
226 area.m_center = zone->Outline()->COutline( 0 ).Centre();
227 m_areas.m_areas.push_back( area );
228
229 wxLogTrace( traceMultichannelTool, wxT("RA '%s', %d footprints\n"), area.m_ruleName, (int) area.m_raFootprints.size() );
230 }
231
232 wxLogTrace( traceMultichannelTool, wxT("Total RAs found: %d\n"), (int) m_areas.m_areas.size() );
233}
234
235
237{
238 for( RULE_AREA& ra : m_areas.m_areas )
239 {
240 if( ra.m_ruleName == aName )
241 return &ra;
242 }
243
244 return nullptr;
245}
246
247
249{
250 std::vector<ZONE*> refRAs;
251
252 auto isSelectedItemAnRA = [] ( EDA_ITEM* aItem ) -> ZONE*
253 {
254 if( aItem->Type() != PCB_ZONE_T )
255 return nullptr;
256 ZONE* zone = static_cast<ZONE*>( aItem );
257 if( !zone->GetIsRuleArea() )
258 return nullptr;
259 if( zone->GetRuleAreaType() != RULE_AREA_TYPE::PLACEMENT )
260 return nullptr;
261 return zone;
262 };
263
264 for( EDA_ITEM* item : selection() )
265 {
266 if( auto zone = isSelectedItemAnRA( item ) )
267 {
268 refRAs.push_back(zone);
269 }
270 else if ( item->Type() == PCB_GROUP_T )
271 {
272 PCB_GROUP *group = static_cast<PCB_GROUP*>( item );
273 for( BOARD_ITEM* grpItem : group->GetItems() )
274 {
275 if( auto grpZone = isSelectedItemAnRA( grpItem ) )
276 {
277 refRAs.push_back( grpZone );
278 }
279 }
280 }
281 }
282
283 if( refRAs.size() != 1 )
284 {
285 frame()->ShowInfoBarError( _( "Please select a single reference Rule Area to copy from." ),
286 true );
287 return 0;
288 }
289
291
292 int status = CheckRACompatibility( refRAs.front() );
293
294 if( status < 0 )
295 return status;
296
297 if( m_areas.m_areas.size() <= 1 )
298 {
299 frame()->ShowInfoBarError( _( "No Rule Areas to repeat layout to have been found." ),
300 true );
301 return 0;
302 }
303
304
306 int ret = dialog.ShowModal();
307
308 if( ret != wxID_OK )
309 return 0;
310
311 return RepeatLayout( aEvent, refRAs.front() );
312}
313
314
316{
317 m_areas.m_refRA = nullptr;
318
319 for( RULE_AREA& ra : m_areas.m_areas )
320 {
321 if( ra.m_area == aRefZone )
322 {
323 m_areas.m_refRA = &ra;
324 break;
325 }
326 }
327
328 if( !m_areas.m_refRA )
329 return -1;
330
331 m_areas.m_compatMap.clear();
332
333 for( RULE_AREA& ra : m_areas.m_areas )
334 {
335 if( ra.m_area == m_areas.m_refRA->m_area )
336 continue;
337
339
341 }
342
343 return 0;
344}
345
346int MULTICHANNEL_TOOL::RepeatLayout( const TOOL_EVENT& aEvent, ZONE* aRefZone )
347{
348 int totalCopied = 0;
349
350 for( auto& targetArea : m_areas.m_compatMap )
351 {
352 if( !targetArea.second.m_doCopy )
353 {
354 wxLogTrace( traceMultichannelTool, wxT("skipping copy to RA '%s' (disabled in dialog)\n"),
355 targetArea.first->m_ruleName );
356 continue;
357 }
358
359 if( !targetArea.second.m_isOk )
360 continue;
361
362 BOARD_COMMIT commit( GetManager(), true );
363
364 std::unordered_set<BOARD_ITEM*> affectedItems;
365 std::unordered_set<BOARD_ITEM*> groupableItems;
366
367 if( !copyRuleAreaContents( targetArea.second.m_matchingComponents, &commit, m_areas.m_refRA,
368 targetArea.first, m_areas.m_options, affectedItems, groupableItems ) )
369 {
370 auto errMsg = wxString::Format(
371 _( "Copy Rule Area contents failed between rule areas '%s' and '%s'." ),
373 targetArea.first->m_area->GetZoneName() );
374
375 commit.Revert();
376 if( Pgm().IsGUI() )
377 {
378 frame()->ShowInfoBarError( errMsg, true );
379 }
380
381 return -1;
382 }
383
384 commit.Push( _( "Repeat layout" ) );
385
387 {
388 // fixme: sth gets weird when creating new zones & grouping them within a single COMMIT
389 BOARD_COMMIT grpCommit( GetManager(), true );
390
391 pruneExistingGroups( grpCommit, affectedItems );
392
393 PCB_GROUP* grp = new PCB_GROUP( board() );
394
395 grpCommit.Add( grp );
396
397 for( auto item : groupableItems )
398 {
399 grpCommit.Stage( item, CHT_GROUP );
400 }
401
402 grpCommit.Push( _( "Group components with their placement rule areas" ) );
403 }
404
405 totalCopied++;
406 }
407
408 if( Pgm().IsGUI() )
409 {
410 frame()->ShowInfoBarMsg( wxString::Format( _( "Copied to %d Rule Areas." ), totalCopied ),
411 true );
412 }
413 return 0;
414}
415
416
417wxString MULTICHANNEL_TOOL::stripComponentIndex( wxString aRef ) const
418{
419 wxString rv;
420
421 // fixme: i'm pretty sure this can be written in a simpler way, but I really suck at figuring
422 // out which wx's built in functions would do it for me. And I hate regexps :-)
423 for( auto k : aRef )
424 {
425 if( !k.IsAscii() )
426 break;
427 char c;
428 k.GetAsChar( &c );
429
430 if( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || ( c == '_' ) )
431 rv.Append( k );
432 else
433 break;
434 }
435
436 return rv;
437}
438
439
440int MULTICHANNEL_TOOL::findRoutedConnections( std::set<BOARD_ITEM*>& aOutput,
441 std::shared_ptr<CONNECTIVITY_DATA> aConnectivity,
442 const SHAPE_POLY_SET& aRAPoly, RULE_AREA* aRA,
443 FOOTPRINT* aFp,
444 const REPEAT_LAYOUT_OPTIONS& aOpts ) const
445{
446 std::set<BOARD_ITEM*> conns;
447
448 for( PAD* pad : aFp->Pads() )
449 {
450 const std::vector<BOARD_CONNECTED_ITEM*> connItems = aConnectivity->GetConnectedItems(
452
453 for( BOARD_CONNECTED_ITEM* item : connItems )
454 conns.insert( item );
455 }
456
457 int count = 0;
458
459 for( BOARD_ITEM* item : conns )
460 {
461 // fixme: respect layer sets assigned to each RA
462
463 if( item->Type() == PCB_PAD_T )
464 continue;
465
466 std::shared_ptr<SHAPE> effShape = item->GetEffectiveShape( item->GetLayer() );
467
468 if( effShape->Collide( &aRAPoly, 0 ) )
469 {
470 aOutput.insert( item );
471 count++;
472 }
473 }
474
475 return count;
476}
477
478
480 RULE_AREA* aRefArea, RULE_AREA* aTargetArea,
482 std::unordered_set<BOARD_ITEM*>& aAffectedItems,
483 std::unordered_set<BOARD_ITEM*>& aGroupableItems )
484{
485 // copy RA shapes first
486 SHAPE_LINE_CHAIN refOutline = aRefArea->m_area->Outline()->COutline( 0 );
487 SHAPE_LINE_CHAIN targetOutline = aTargetArea->m_area->Outline()->COutline( 0 );
488
489 VECTOR2I disp = aTargetArea->m_center - aRefArea->m_center;
490
491 SHAPE_POLY_SET refPoly;
492 refPoly.AddOutline( refOutline );
493 refPoly.CacheTriangulation( false );
494
495 SHAPE_POLY_SET targetPoly;
496
497 SHAPE_LINE_CHAIN newTargetOutline( refOutline );
498 newTargetOutline.Move( disp );
499 targetPoly.AddOutline( newTargetOutline );
500 targetPoly.CacheTriangulation( false );
501
502 auto connectivity = board()->GetConnectivity();
503
504 aCommit->Modify( aTargetArea->m_area );
505
506 aAffectedItems.insert( aTargetArea->m_area );
507 aGroupableItems.insert( aTargetArea->m_area );
508
509 if( aOpts.m_copyRouting )
510 {
511 std::set<BOARD_ITEM*> refRouting;
512 std::set<BOARD_ITEM*> targetRouting;
513
514 wxLogTrace( traceMultichannelTool, wxT("copying routing: %d fps\n"), (int) aMatches.size() );
515
516 for( auto& fpPair : aMatches )
517 {
518 findRoutedConnections( targetRouting, connectivity, targetPoly, aTargetArea,
519 fpPair.second, aOpts );
520 findRoutedConnections( refRouting, connectivity, refPoly, aRefArea, fpPair.first,
521 aOpts );
522
523 wxLogTrace( traceMultichannelTool, wxT("target-routes %d\n"), (int) targetRouting.size() );
524 }
525
526 for( BOARD_ITEM* item : targetRouting )
527 {
528 if( item->IsLocked() && !aOpts.m_includeLockedItems )
529 continue;
530
531 // item already removed
532 if( aCommit->GetStatus( item ) != 0 )
533 continue;
534
535 if( aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
536 {
537 aAffectedItems.insert( item );
538 aCommit->Remove( item );
539 }
540 }
541
542 for( BOARD_ITEM* item : refRouting )
543 {
544 if( !aRefArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
545 continue;
546 if( !aTargetArea->m_area->GetLayerSet().Contains( item->GetLayer() ) )
547 continue;
548
549 BOARD_ITEM* copied = static_cast<BOARD_ITEM*>( item->Clone() );
550
551 copied->Move( disp );
552 aGroupableItems.insert( copied );
553 aCommit->Add( copied );
554 }
555 }
556
557
558 aTargetArea->m_area->RemoveAllContours();
559 aTargetArea->m_area->AddPolygon( newTargetOutline );
560 aTargetArea->m_area->UnHatchBorder();
561 aTargetArea->m_area->HatchBorder();
562
563 if( aOpts.m_copyPlacement )
564 {
565 for( auto& fpPair : aMatches )
566 {
567 FOOTPRINT* refFP = fpPair.first;
568 FOOTPRINT* targetFP = fpPair.second;
569
570 if( !aRefArea->m_area->GetLayerSet().Contains( refFP->GetLayer() ) )
571 {
572 wxLogTrace( traceMultichannelTool, wxT( "discard ref:%s (ref layer)\n" ),
573 refFP->GetReference() );
574 continue;
575 }
576 if( !aTargetArea->m_area->GetLayerSet().Contains( refFP->GetLayer() ) )
577 {
578 wxLogTrace( traceMultichannelTool, wxT( "discard ref:%s (target layer)\n" ),
579 refFP->GetReference() );
580 continue;
581 }
582
583 if( targetFP->IsLocked() && !aOpts.m_includeLockedItems )
584 continue;
585
586 aCommit->Modify( targetFP );
587
588 targetFP->SetLayerAndFlip( refFP->GetLayer() );
589 targetFP->SetOrientation( refFP->GetOrientation() );
590 VECTOR2I targetPos = refFP->GetPosition() + disp;
591 targetFP->SetPosition( targetPos );
592 targetFP->Reference().SetTextAngle( refFP->Reference().GetTextAngle() );
593 targetFP->Reference().SetPosition( refFP->Reference().GetPosition() + disp );
594 targetFP->Value().SetTextAngle( refFP->Value().GetTextAngle() );
595 targetFP->Value().SetPosition( refFP->Value().GetPosition() + disp );
596
597 aAffectedItems.insert( targetFP );
598 aGroupableItems.insert( targetFP );
599 }
600 }
601
602 return true;
603}
604
605
607{
608 using namespace TMATCH;
609
610 std::unique_ptr<CONNECTION_GRAPH> cgRef ( CONNECTION_GRAPH::BuildFromFootprintSet( aRefArea->m_raFootprints ) );
611 std::unique_ptr<CONNECTION_GRAPH> cgTarget ( CONNECTION_GRAPH::BuildFromFootprintSet( aTargetArea->m_raFootprints ) );
612
613 auto status = cgRef->FindIsomorphism( cgTarget.get(), aMatches.m_matchingComponents );
614
615 switch( status )
616 {
617 case CONNECTION_GRAPH::ST_OK:
618 aMatches.m_isOk = true;
619 aMatches.m_errorMsg = _("OK");
620 break;
621 case CONNECTION_GRAPH::ST_EMPTY:
622 aMatches.m_isOk = false;
623 aMatches.m_errorMsg = _("One or both of the areas has no components assigned.");
624 break;
625 case CONNECTION_GRAPH::ST_COMPONENT_COUNT_MISMATCH:
626 aMatches.m_isOk = false;
627 aMatches.m_errorMsg = _("Component count mismatch");
628 break;
629 case CONNECTION_GRAPH::ST_ITERATION_COUNT_EXCEEDED:
630 aMatches.m_isOk = false;
631 aMatches.m_errorMsg = _("Iteration count exceeded (timeout)");
632 break;
633 case CONNECTION_GRAPH::ST_TOPOLOGY_MISMATCH:
634 aMatches.m_isOk = false;
635 aMatches.m_errorMsg = _("Topology mismatch");
636 break;
637 default:
638 break;
639 }
640
641 return (status == TMATCH::CONNECTION_GRAPH::ST_OK );
642}
643
644
645bool MULTICHANNEL_TOOL::pruneExistingGroups( COMMIT& aCommit, const std::unordered_set<BOARD_ITEM*>& aItemsToRemove )
646{
647 for( PCB_GROUP* grp : board()->Groups() )
648 {
649 std::unordered_set<BOARD_ITEM*>& grpItems = grp->GetItems();
650 size_t n_erased = 0;
651
652 for( auto refItem : grpItems )
653 {
654 //printf("check ref %p [%s]\n", refItem, refItem->GetTypeDesc().c_str().AsChar() );
655 for ( auto& testItem : aItemsToRemove )
656 {
657
658 if( refItem->m_Uuid == testItem->m_Uuid )
659 {
660 aCommit.Stage( refItem, CHT_UNGROUP );
661 n_erased++;
662 }
663 }
664 }
665
666 if( n_erased == grpItems.size() )
667 {
668 aCommit.Stage( grp, CHT_REMOVE );
669 }
670
671 //printf("Grp %p items %d pruned %d air %d\n", grp,grpItems.size(), (int) n_erased, (int) aItemsToRemove.size() );
672 }
673
674 return false;
675}
676
678{
679 if( Pgm().IsGUI() )
680 {
681 QuerySheets();
682
683 if( m_areas.m_areas.size() <= 1 )
684 {
685 frame()->ShowInfoBarError( _( "Cannot auto-generate any placement areas because the "
686 "schematic has only one or no hierarchical sheet(s)." ),
687 true );
688 return 0;
689 }
690
691
693 int ret = dialog.ShowModal();
694
695 if( ret != wxID_OK )
696 return 0;
697 }
698
699 for( ZONE* zone : board()->Zones() )
700 {
701 if( !zone->GetIsRuleArea() )
702 continue;
703 if( zone->GetRuleAreaType() != RULE_AREA_TYPE::PLACEMENT )
704 continue;
705
706 std::set<FOOTPRINT*> components;
707 identifyComponentsInRuleArea( zone, components );
708
709 if( components.empty() )
710 continue;
711
712 for( auto& ra : m_areas.m_areas )
713 {
714 if( components == ra.m_sheetComponents )
715 {
716 wxLogTrace( traceMultichannelTool,
717 wxT( "Placement rule area for sheet '%s' already exists as '%s'\n" ),
718 ra.m_sheetPath, zone->GetZoneName() );
719
720 ra.m_oldArea = zone;
721 ra.m_existsAlready = true;
722 }
723 }
724 }
725
726 wxLogTrace( traceMultichannelTool,
727 wxT( "%d placement areas found\n" ), (int) m_areas.m_areas.size() );
728
729 BOARD_COMMIT commit( GetManager(), true );
730
731 for( RULE_AREA& ra : m_areas.m_areas )
732 {
733 if( !ra.m_generateEnabled )
734 continue;
736 continue;
737
738 auto raOutline = buildRAOutline( ra.m_sheetComponents, 100000 );
739
740 std::unique_ptr<ZONE> newZone( new ZONE( board() ) );
741
742 newZone->SetZoneName( wxString::Format( wxT( "auto-placement-area-%s" ), ra.m_sheetPath ) );
743
744 wxLogTrace( traceMultichannelTool,
745 wxT( "Generated rule area '%s' (%d components)\n" ),
746 newZone->GetZoneName(),
747 (int) ra.m_sheetComponents.size() );
748
749 newZone->SetIsRuleArea( true );
750 newZone->SetLayerSet( LSET::AllCuMask() );
751 newZone->SetRuleAreaType( RULE_AREA_TYPE::PLACEMENT );
752 newZone->SetRuleAreaExpression(
753 wxString::Format( wxT( "A.memberOfSheet('%s')" ), ra.m_sheetPath ) );
754 newZone->AddPolygon( raOutline );
755 newZone->SetHatchStyle( ZONE_BORDER_DISPLAY_STYLE::NO_HATCH );
756
757 if( ra.m_existsAlready )
758 {
759 commit.Remove( ra.m_oldArea );
760 }
761
762 ra.m_area = newZone.get();
763 commit.Add( newZone.release() );
764
765 }
766
767 commit.Push( _( "Auto-generate placement rule areas" ) );
768
769 // fixme: handle corner cases where the items belonging to a Rule Area already
770 // belong to other groups.
771
773 {
774 // fixme: sth gets weird when creating new zones & grouping them within a single COMMIT
775 BOARD_COMMIT grpCommit( GetManager(), true );
776
777 for( RULE_AREA& ra : m_areas.m_areas )
778 {
779 if( !ra.m_generateEnabled )
780 continue;
782 continue;
783
784 std::unordered_set<BOARD_ITEM*> toPrune;
785
786 std::copy( ra.m_sheetComponents.begin(), ra.m_sheetComponents.end(),
787 std::inserter( toPrune, toPrune.begin() ) );
788
789 if( ra.m_existsAlready )
790 toPrune.insert( ra.m_area );
791
792 pruneExistingGroups( grpCommit, toPrune );
793
794 PCB_GROUP* grp = new PCB_GROUP( board() );
795
796 grpCommit.Add( grp );
797 grpCommit.Stage( ra.m_area, CHT_GROUP );
798
799 for( auto fp : ra.m_sheetComponents )
800 {
801 grpCommit.Stage( fp, CHT_GROUP );
802 }
803 }
804 grpCommit.Push( _( "Group components with their placement rule areas" ) );
805 }
806
807
808 return true;
809}
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Revert the commit by restoring the modified items state.
COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr) override
virtual void Revert() override
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
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 Move(const VECTOR2I &aMoveVector)
Move this object.
Definition: board_item.h:330
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Return a list of missing connections between components/tracks.
Definition: board.h:474
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)
Notify observers that aItem has been removed.
Definition: commit.h:92
virtual COMMIT & Stage(EDA_ITEM *aItem, CHANGE_TYPE aChangeType, BASE_SCREEN *aScreen=nullptr)
Definition: commit.cpp:48
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Create an undo entry for an item that has been already modified.
Definition: commit.h:105
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Notify observers that aItem has been added.
Definition: commit.h:80
int GetStatus(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Definition: commit.cpp:130
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:89
const EDA_ANGLE & GetTextAngle() const
Definition: eda_text.h:130
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition: eda_text.cpp:204
void SetPosition(const VECTOR2I &aPos) override
Definition: footprint.cpp:2348
EDA_ANGLE GetOrientation() const
Definition: footprint.h:226
void SetOrientation(const EDA_ANGLE &aNewAngle)
Definition: footprint.cpp:2420
PCB_FIELD & Value()
read/write accessors:
Definition: footprint.h:637
std::deque< PAD * > & Pads()
Definition: footprint.h:205
PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: footprint.h:235
bool IsLocked() const override
Definition: footprint.h:410
void SetLayerAndFlip(PCB_LAYER_ID aLayer)
Used as Layer property setter – performs a flip if necessary to set the footprint layer.
Definition: footprint.cpp:2280
PCB_FIELD & Reference()
Definition: footprint.h:638
const wxString & GetReference() const
Definition: footprint.h:601
VECTOR2I GetPosition() const override
Definition: footprint.h:223
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)
bool Contains(PCB_LAYER_ID aLayer)
See if the layer set contains a PCB layer.
Definition: lset.h:79
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:732
int CheckRACompatibility(ZONE *aRefZone)
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 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)
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)
std::set< FOOTPRINT * > queryComponentsInSheet(wxString aSheetName)
int RepeatLayout(const TOOL_EVENT &aEvent, ZONE *aRefZone)
int AutogenerateRuleAreas(const TOOL_EVENT &aEvent)
bool identifyComponentsInRuleArea(ZONE *aRuleArea, std::set< FOOTPRINT * > &aComponents)
wxString stripComponentIndex(wxString aRef) 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)
Definition: pad.h:54
void SetItems(BOARD_ITEM *a, BOARD_ITEM *b=nullptr)
static TOOL_ACTION repeatLayout
Definition: pcb_actions.h:584
static TOOL_ACTION generatePlacementRuleAreas
Definition: pcb_actions.h:585
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:52
virtual VECTOR2I GetPosition() const override
Definition: pcb_text.h:82
virtual void SetPosition(const VECTOR2I &aPos) override
Definition: pcb_text.h:87
T * frame() const
BOARD * board() const
const PCB_SELECTION & selection() const
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
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 SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Simplify(int aMaxError=0)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
int SegmentCount() const
Return the number of segments in this line chain.
const SEG CSegment(int aIndex) const
Return a constant copy of the aIndex segment in the line chain.
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
Generic, UI-independent tool event.
Definition: tool_event.h:167
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).
Handle a list of polygons defining a copper zone.
Definition: zone.h:73
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:711
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition: zone.cpp:804
RULE_AREA_TYPE GetRuleAreaType() const
Definition: zone.h:712
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition: zone.cpp:930
const wxString & GetRuleAreaExpression() const
Definition: zone.h:713
SHAPE_POLY_SET * Outline()
Definition: zone.h:337
const wxString & GetZoneName() const
Definition: zone.h:132
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:130
void UnHatchBorder()
Clear the zone's hatch.
Definition: zone.cpp:916
void RemoveAllContours(void)
Definition: zone.h:550
@ CHT_GROUP
Definition: commit.h:45
@ CHT_REMOVE
Definition: commit.h:43
@ CHT_UNGROUP
Definition: commit.h:46
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)
static const wxString traceMultichannelTool
std::map< FOOTPRINT *, FOOTPRINT * > COMPONENT_MATCHES
Definition: topo_match.h:148
Class to handle a set of BOARD_ITEMs.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: pgm_base.cpp:1059
see class PGM_BASE
std::unordered_map< RULE_AREA *, RULE_AREA_COMPAT_DATA > m_compatMap
RULE_AREA * m_refRA
REPEAT_LAYOUT_OPTIONS m_options
std::vector< RULE_AREA > m_areas
TMATCH::COMPONENT_MATCHES m_matchingComponents
VECTOR2I m_center
wxString m_sheetName
std::set< FOOTPRINT * > m_sheetComponents
bool m_existsAlready
std::set< FOOTPRINT * > m_raFootprints
ZONE * m_oldArea
wxString m_ruleName
wxString m_sheetPath
bool m_generateEnabled
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
Definition: typeinfo.h:88
@ PCB_VIA_T
class PCB_VIA, a via (like a track segment on a copper layer)
Definition: typeinfo.h:97
@ 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_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87
@ PCB_ARC_T
class PCB_ARC, an arc track segment on a copper layer
Definition: typeinfo.h:98
@ PCB_TRACE_T
class PCB_TRACK, a track segment (segment on a copper layer)
Definition: typeinfo.h:96
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:676