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