KiCad PCB EDA Suite
Loading...
Searching...
No Matches
zone.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2017 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <[email protected]>
6 * Copyright (C) 1992-2024 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <bitmaps.h>
28#include <geometry/shape_null.h>
29#include <pcb_edit_frame.h>
30#include <pcb_screen.h>
31#include <board.h>
33#include <pad.h>
34#include <zone.h>
35#include <footprint.h>
36#include <string_utils.h>
37#include <math_for_graphics.h>
41#include <trigo.h>
42#include <i18n_utility.h>
43#include <mutex>
44
45
48 m_Poly( nullptr ),
49 m_teardropType( TEARDROP_TYPE::TD_NONE ),
50 m_isFilled( false ),
51 m_CornerSelection( nullptr ),
52 m_area( 0.0 ),
53 m_outlinearea( 0.0 )
54{
55 m_Poly = new SHAPE_POLY_SET(); // Outlines
56 SetLocalFlags( 0 ); // flags temporary used in zone calculations
57 m_fillVersion = 5; // set the "old" way to build filled polygon areas (< 6.0.x)
58
59 if( GetParentFootprint() )
60 SetIsRuleArea( true ); // Zones living in footprints have the rule area option
61
62 if( aParent->GetBoard() )
64 else
66
67 m_needRefill = false; // True only after edits.
68}
69
70
71ZONE::ZONE( const ZONE& aZone ) :
72 BOARD_CONNECTED_ITEM( aZone ),
73 m_Poly( nullptr ),
74 m_CornerSelection( nullptr )
75{
77}
78
79
80ZONE& ZONE::operator=( const ZONE& aOther )
81{
83
85
86 return *this;
87}
88
89
91{
92 delete m_Poly;
93 delete m_CornerSelection;
94
95 if( BOARD* board = GetBoard() )
96 board->IncrementTimeStamp();
97}
98
99
101{
102 // members are expected non initialize in this.
103 // InitDataFromSrcInCopyCtor() is expected to be called only from a copy constructor.
104
105 // Copy only useful EDA_ITEM flags:
106 m_flags = aZone.m_flags;
108
109 // Replace the outlines for aZone outlines.
110 delete m_Poly;
111 m_Poly = new SHAPE_POLY_SET( *aZone.m_Poly );
112
115 m_zoneName = aZone.m_zoneName;
116 m_priority = aZone.m_priority;
118 SetLayerSet( aZone.GetLayerSet() );
119
125
127 m_ZoneClearance = aZone.m_ZoneClearance; // clearance value
132
133 m_isFilled = aZone.m_isFilled;
136
139
140 m_fillMode = aZone.m_fillMode; // solid vs. hatched
142 m_hatchGap = aZone.m_hatchGap;
148
149 // For corner moving, corner index to drag, or nullptr if no selection
150 delete m_CornerSelection;
151 m_CornerSelection = nullptr;
152
153 for( PCB_LAYER_ID layer : aZone.GetLayerSet().Seq() )
154 {
155 std::shared_ptr<SHAPE_POLY_SET> fill = aZone.m_FilledPolysList.at( layer );
156
157 if( fill )
158 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>( *fill );
159 else
160 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
161
162 m_filledPolysHash[layer] = aZone.m_filledPolysHash.at( layer );
163 m_insulatedIslands[layer] = aZone.m_insulatedIslands.at( layer );
164 }
165
169
170 SetLocalFlags( aZone.GetLocalFlags() );
171
172 m_netinfo = aZone.m_netinfo;
173 m_area = aZone.m_area;
175}
176
177
179{
180 return new ZONE( *this );
181}
182
183
184bool ZONE::HigherPriority( const ZONE* aOther ) const
185{
186 // Teardrops are always higher priority than regular zones, so if one zone is a teardrop
187 // and the other is not, then return higher priority as the teardrop
188 if( ( m_teardropType == TEARDROP_TYPE::TD_NONE )
189 ^ ( aOther->m_teardropType == TEARDROP_TYPE::TD_NONE ) )
190 {
191 return static_cast<int>( m_teardropType ) > static_cast<int>( aOther->m_teardropType );
192 }
193
194 if( m_priority != aOther->m_priority )
195 return m_priority > aOther->m_priority;
196
197 return m_Uuid > aOther->m_Uuid;
198}
199
200
201bool ZONE::SameNet( const ZONE* aOther ) const
202{
203 return GetNetCode() == aOther->GetNetCode();
204}
205
206
208{
209 bool change = false;
210
211 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
212 {
213 change |= !pair.second->IsEmpty();
214 m_insulatedIslands[pair.first].clear();
215 pair.second->RemoveAllContours();
216 }
217
218 m_isFilled = false;
219 m_fillFlags.reset();
220
221 return change;
222}
223
224
226{
227 return HasFlag( COURTYARD_CONFLICT );
228}
229
230
232{
233 return GetCornerPosition( 0 );
234}
235
236
238{
239 if( m_layerSet.count() == 1 )
240 return m_layerSet.UIOrder()[0];
241 else
242 return UNDEFINED_LAYER;
243}
244
245
247{
248 if( m_layerSet.count() )
249 return m_layerSet.UIOrder()[0];
250 else
251 return UNDEFINED_LAYER;
252}
253
254
256{
257 return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
258}
259
260
262{
263 SetLayerSet( LSET( aLayer ) );
264}
265
266
267void ZONE::SetLayerSet( LSET aLayerSet )
268{
269 if( aLayerSet.count() == 0 )
270 return;
271
272 if( m_layerSet != aLayerSet )
273 {
274 SetNeedRefill( true );
275
276 UnFill();
277
278 m_FilledPolysList.clear();
279 m_filledPolysHash.clear();
280 m_insulatedIslands.clear();
281
282 for( PCB_LAYER_ID layer : aLayerSet.Seq() )
283 {
284 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
285 m_filledPolysHash[layer] = {};
286 m_insulatedIslands[layer] = {};
287 }
288 }
289
290 m_layerSet = aLayerSet;
291}
292
293
294void ZONE::ViewGetLayers( int aLayers[], int& aCount ) const
295{
296 aCount = 0;
297 LSEQ layers = m_layerSet.Seq();
298
299 for( PCB_LAYER_ID layer : m_layerSet.Seq() )
300 {
301 aLayers[ aCount++ ] = layer; // For outline (always full opacity)
302 aLayers[ aCount++ ] = layer + static_cast<int>( LAYER_ZONE_START ); // For fill (obeys global zone opacity)
303 }
304
305 if( IsConflicting() )
306 aLayers[ aCount++ ] = LAYER_CONFLICTS_SHADOW;
307}
308
309
310double ZONE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
311{
312 constexpr double HIDE = std::numeric_limits<double>::max();
313
314 if( !aView )
315 return 0;
316
317 if( !aView->IsLayerVisible( LAYER_ZONES ) )
318 return HIDE;
319
320 if( FOOTPRINT* parentFP = GetParentFootprint() )
321 {
322 bool flipped = parentFP->GetLayer() == B_Cu;
323
324 // Handle Render tab switches
325 if( !flipped && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
326 return HIDE;
327
328 if( flipped && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
329 return HIDE;
330 }
331
332 // Other layers are shown without any conditions
333 return 0.0;
334}
335
336
337bool ZONE::IsOnLayer( PCB_LAYER_ID aLayer ) const
338{
339 return m_layerSet.test( aLayer );
340}
341
342
344{
345 if( const BOARD* board = GetBoard() )
346 {
347 std::unordered_map<const ZONE*, BOX2I>& cache = board->m_ZoneBBoxCache;
348
349 {
350 std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
351
352 auto cacheIter = cache.find( this );
353
354 if( cacheIter != cache.end() )
355 return cacheIter->second;
356 }
357
358 BOX2I bbox = m_Poly->BBox();
359
360 {
361 std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
362 cache[ this ] = bbox;
363 }
364
365 return bbox;
366 }
367
368 return m_Poly->BBox();
369}
370
371
373{
374 // GetBoundingBox() will cache it for us, and there's no sense duplicating the somewhat tricky
375 // locking code.
377}
378
379
380int ZONE::GetThermalReliefGap( PAD* aPad, wxString* aSource ) const
381{
382 if( aPad->GetLocalThermalGapOverride() == 0 )
383 {
384 if( aSource )
385 *aSource = _( "zone" );
386
387 return m_thermalReliefGap;
388 }
389
390 return aPad->GetLocalThermalGapOverride( aSource );
391
392}
393
394
395void ZONE::SetCornerRadius( unsigned int aRadius )
396{
397 if( m_cornerRadius != aRadius )
398 SetNeedRefill( true );
399
400 m_cornerRadius = aRadius;
401}
402
403
405
406
408{
409 if( !m_filledPolysHash.count( aLayer ) )
410 return g_nullPoly.GetHash();
411 else
412 return m_filledPolysHash.at( aLayer );
413}
414
415
417{
418 if( !m_FilledPolysList.count( aLayer ) )
420 else
421 m_filledPolysHash[aLayer] = m_FilledPolysList.at( aLayer )->GetHash();
422}
423
424
425bool ZONE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
426{
427 // When looking for an "exact" hit aAccuracy will be 0 which works poorly for very thin
428 // lines. Give it a floor.
429 int accuracy = std::max( aAccuracy, pcbIUScale.mmToIU( 0.1 ) );
430
431 return HitTestForCorner( aPosition, accuracy * 2 ) || HitTestForEdge( aPosition, accuracy );
432}
433
434
435bool ZONE::HitTestForCorner( const VECTOR2I& refPos, int aAccuracy,
436 SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
437{
438 return m_Poly->CollideVertex( VECTOR2I( refPos ), aCornerHit, aAccuracy );
439}
440
441
442bool ZONE::HitTestForEdge( const VECTOR2I& refPos, int aAccuracy,
443 SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
444{
445 return m_Poly->CollideEdge( VECTOR2I( refPos ), aCornerHit, aAccuracy );
446}
447
448
449bool ZONE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
450{
451 // Calculate bounding box for zone
452 BOX2I bbox = GetBoundingBox();
453 bbox.Normalize();
454
455 BOX2I arect = aRect;
456 arect.Normalize();
457 arect.Inflate( aAccuracy );
458
459 if( aContained )
460 {
461 return arect.Contains( bbox );
462 }
463 else
464 {
465 // Fast test: if aBox is outside the polygon bounding box, rectangles cannot intersect
466 if( !arect.Intersects( bbox ) )
467 return false;
468
469 int count = m_Poly->TotalVertices();
470
471 for( int ii = 0; ii < count; ii++ )
472 {
473 VECTOR2I vertex = m_Poly->CVertex( ii );
474 VECTOR2I vertexNext = m_Poly->CVertex( ( ii + 1 ) % count );
475
476 // Test if the point is within the rect
477 if( arect.Contains( vertex ) )
478 return true;
479
480 // Test if this edge intersects the rect
481 if( arect.Intersects( vertex, vertexNext ) )
482 return true;
483 }
484
485 return false;
486 }
487}
488
489
490std::optional<int> ZONE::GetLocalClearance() const
491{
492 return m_isRuleArea ? 0 : m_ZoneClearance;
493}
494
495
496bool ZONE::HitTestFilledArea( PCB_LAYER_ID aLayer, const VECTOR2I& aRefPos, int aAccuracy ) const
497{
498 // Rule areas have no filled area, but it's generally nice to treat their interior as if it were
499 // filled so that people don't have to select them by their outline (which is min-width)
500 if( GetIsRuleArea() )
501 return m_Poly->Contains( aRefPos, -1, aAccuracy );
502
503 if( !m_FilledPolysList.count( aLayer ) )
504 return false;
505
506 return m_FilledPolysList.at( aLayer )->Contains( aRefPos, -1, aAccuracy );
507}
508
509
510bool ZONE::HitTestCutout( const VECTOR2I& aRefPos, int* aOutlineIdx, int* aHoleIdx ) const
511{
512 // Iterate over each outline polygon in the zone and then iterate over
513 // each hole it has to see if the point is in it.
514 for( int i = 0; i < m_Poly->OutlineCount(); i++ )
515 {
516 for( int j = 0; j < m_Poly->HoleCount( i ); j++ )
517 {
518 if( m_Poly->Hole( i, j ).PointInside( aRefPos ) )
519 {
520 if( aOutlineIdx )
521 *aOutlineIdx = i;
522
523 if( aHoleIdx )
524 *aHoleIdx = j;
525
526 return true;
527 }
528 }
529 }
530
531 return false;
532}
533
534
535void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
536{
537 wxString msg = GetFriendlyName();
538
539 // Display Cutout instead of Outline for holes inside a zone (i.e. when num contour !=0).
540 // Check whether the selected corner is in a hole; i.e., in any contour but the first one.
541 if( m_CornerSelection != nullptr && m_CornerSelection->m_contour > 0 )
542 msg << wxT( " " ) << _( "Cutout" );
543
544 aList.emplace_back( _( "Type" ), msg );
545
546 if( GetIsRuleArea() )
547 {
548 msg.Empty();
549
550 if( GetDoNotAllowVias() )
551 AccumulateDescription( msg, _( "No vias" ) );
552
553 if( GetDoNotAllowTracks() )
554 AccumulateDescription( msg, _( "No tracks" ) );
555
556 if( GetDoNotAllowPads() )
557 AccumulateDescription( msg, _( "No pads" ) );
558
560 AccumulateDescription( msg, _( "No copper zones" ) );
561
563 AccumulateDescription( msg, _( "No footprints" ) );
564
565 if( !msg.IsEmpty() )
566 aList.emplace_back( _( "Restrictions" ), msg );
567 }
568 else if( IsOnCopperLayer() )
569 {
570 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
571 {
572 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
573
574 aList.emplace_back( _( "Resolved Netclass" ),
575 UnescapeString( GetEffectiveNetClass()->GetName() ) );
576 }
577
578 // Display priority level
579 aList.emplace_back( _( "Priority" ),
580 wxString::Format( wxT( "%d" ), GetAssignedPriority() ) );
581 }
582
583 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
584 {
585 if( IsLocked() )
586 aList.emplace_back( _( "Status" ), _( "Locked" ) );
587 }
588
589 LSEQ layers = m_layerSet.Seq();
590 wxString layerDesc;
591
592 if( layers.size() == 1 )
593 {
594 layerDesc.Printf( _( "%s" ), GetBoard()->GetLayerName( layers[0] ) );
595 }
596 else if (layers.size() == 2 )
597 {
598 layerDesc.Printf( _( "%s and %s" ),
599 GetBoard()->GetLayerName( layers[0] ),
600 GetBoard()->GetLayerName( layers[1] ) );
601 }
602 else if (layers.size() == 3 )
603 {
604 layerDesc.Printf( _( "%s, %s and %s" ),
605 GetBoard()->GetLayerName( layers[0] ),
606 GetBoard()->GetLayerName( layers[1] ),
607 GetBoard()->GetLayerName( layers[2] ) );
608 }
609 else if( layers.size() > 3 )
610 {
611 layerDesc.Printf( _( "%s, %s and %d more" ),
612 GetBoard()->GetLayerName( layers[0] ),
613 GetBoard()->GetLayerName( layers[1] ),
614 static_cast<int>( layers.size() - 2 ) );
615 }
616
617 aList.emplace_back( _( "Layer" ), layerDesc );
618
619 if( !m_zoneName.empty() )
620 aList.emplace_back( _( "Name" ), m_zoneName );
621
622 switch( m_fillMode )
623 {
624 case ZONE_FILL_MODE::POLYGONS: msg = _( "Solid" ); break;
625 case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break;
626 default: msg = _( "Unknown" ); break;
627 }
628
629 aList.emplace_back( _( "Fill Mode" ), msg );
630
631 aList.emplace_back( _( "Filled Area" ),
632 aFrame->MessageTextFromValue( m_area, true, EDA_DATA_TYPE::AREA ) );
633
634 wxString source;
635 int clearance = GetOwnClearance( UNDEFINED_LAYER, &source );
636
637 if( !source.IsEmpty() )
638 {
639 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
640 aFrame->MessageTextFromValue( clearance ) ),
641 wxString::Format( _( "(from %s)" ),
642 source ) );
643 }
644
645 if( !m_FilledPolysList.empty() )
646 {
647 int count = 0;
648
649 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& ii: m_FilledPolysList )
650 count += ii.second->TotalVertices();
651
652 aList.emplace_back( _( "Corner Count" ), wxString::Format( wxT( "%d" ), count ) );
653 }
654}
655
656
657void ZONE::Move( const VECTOR2I& offset )
658{
659 /* move outlines */
660 m_Poly->Move( offset );
661
662 HatchBorder();
663
664 /* move fills */
665 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
666 pair.second->Move( offset );
667
668 /*
669 * move boundingbox cache
670 *
671 * While the cache will get nuked at the conclusion of the operation, we use it for some
672 * things (such as drawing the parent group) during the move.
673 */
674 if( GetBoard() )
675 {
676 auto it = GetBoard()->m_ZoneBBoxCache.find( this );
677
678 if( it != GetBoard()->m_ZoneBBoxCache.end() )
679 it->second.Move( offset );
680 }
681}
682
683
684wxString ZONE::GetFriendlyName() const
685{
686 if( GetIsRuleArea() )
687 return _( "Rule Area" );
688 else if( IsTeardropArea() )
689 return _( "Teardrop Area" );
690 else if( IsOnCopperLayer() )
691 return _( "Copper Zone" );
692 else
693 return _( "Non-copper Zone" );
694}
695
696
697void ZONE::MoveEdge( const VECTOR2I& offset, int aEdge )
698{
699 int next_corner;
700
701 if( m_Poly->GetNeighbourIndexes( aEdge, nullptr, &next_corner ) )
702 {
703 m_Poly->SetVertex( aEdge, m_Poly->CVertex( aEdge ) + VECTOR2I( offset ) );
704 m_Poly->SetVertex( next_corner, m_Poly->CVertex( next_corner ) + VECTOR2I( offset ) );
705 HatchBorder();
706
707 SetNeedRefill( true );
708 }
709}
710
711
712void ZONE::Rotate( const VECTOR2I& aCentre, const EDA_ANGLE& aAngle )
713{
714 m_Poly->Rotate( aAngle, aCentre );
715 HatchBorder();
716
717 /* rotate filled areas: */
718 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
719 pair.second->Rotate( aAngle, aCentre );
720}
721
722
723void ZONE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
724{
725 Mirror( aCentre, aFlipLeftRight );
726
727 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> fillsCopy;
728
729 for( auto& [oldLayer, shapePtr] : m_FilledPolysList )
730 {
731 fillsCopy[oldLayer] = *shapePtr;
732 }
733
734 SetLayerSet( FlipLayerMask( GetLayerSet(), GetBoard()->GetCopperLayerCount() ) );
735
736 for( auto& [oldLayer, shape] : fillsCopy )
737 {
738 PCB_LAYER_ID newLayer = FlipLayer( oldLayer, GetBoard()->GetCopperLayerCount() );
739 SetFilledPolysList( newLayer, shape );
740 }
741}
742
743
744void ZONE::Mirror( const VECTOR2I& aMirrorRef, bool aMirrorLeftRight )
745{
746 m_Poly->Mirror( aMirrorLeftRight, !aMirrorLeftRight, aMirrorRef );
747
748 HatchBorder();
749
750 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
751 pair.second->Mirror( aMirrorLeftRight, !aMirrorLeftRight, aMirrorRef );
752}
753
754
755void ZONE::RemoveCutout( int aOutlineIdx, int aHoleIdx )
756{
757 // Ensure the requested cutout is valid
758 if( m_Poly->OutlineCount() < aOutlineIdx || m_Poly->HoleCount( aOutlineIdx ) < aHoleIdx )
759 return;
760
761 SHAPE_POLY_SET cutPoly( m_Poly->Hole( aOutlineIdx, aHoleIdx ) );
762
763 // Add the cutout back to the zone
765
766 SetNeedRefill( true );
767}
768
769
770void ZONE::AddPolygon( const SHAPE_LINE_CHAIN& aPolygon )
771{
772 wxASSERT( aPolygon.IsClosed() );
773
774 // Add the outline as a new polygon in the polygon set
775 if( m_Poly->OutlineCount() == 0 )
776 m_Poly->AddOutline( aPolygon );
777 else
778 m_Poly->AddHole( aPolygon );
779
780 SetNeedRefill( true );
781}
782
783
784void ZONE::AddPolygon( std::vector<VECTOR2I>& aPolygon )
785{
786 if( aPolygon.empty() )
787 return;
788
789 SHAPE_LINE_CHAIN outline;
790
791 // Create an outline and populate it with the points of aPolygon
792 for( const VECTOR2I& pt : aPolygon )
793 outline.Append( pt );
794
795 outline.SetClosed( true );
796
797 AddPolygon( outline );
798}
799
800
801bool ZONE::AppendCorner( VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication )
802{
803 // Ensure the main outline exists:
804 if( m_Poly->OutlineCount() == 0 )
806
807 // If aHoleIdx >= 0, the corner musty be added to the hole, index aHoleIdx.
808 // (remember: the index of the first hole is 0)
809 // Return error if it does not exist.
810 if( aHoleIdx >= m_Poly->HoleCount( 0 ) )
811 return false;
812
813 m_Poly->Append( aPosition.x, aPosition.y, -1, aHoleIdx, aAllowDuplication );
814
815 SetNeedRefill( true );
816
817 return true;
818}
819
820
821wxString ZONE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
822{
823 LSEQ layers = m_layerSet.Seq();
824 wxString layerDesc;
825
826 if( layers.size() == 1 )
827 {
828 layerDesc.Printf( _( "on %s" ), GetBoard()->GetLayerName( layers[0] ) );
829 }
830 else if (layers.size() == 2 )
831 {
832 layerDesc.Printf( _( "on %s and %s" ),
833 GetBoard()->GetLayerName( layers[0] ),
834 GetBoard()->GetLayerName( layers[1] ) );
835 }
836 else if (layers.size() == 3 )
837 {
838 layerDesc.Printf( _( "on %s, %s and %s" ),
839 GetBoard()->GetLayerName( layers[0] ),
840 GetBoard()->GetLayerName( layers[1] ),
841 GetBoard()->GetLayerName( layers[2] ) );
842 }
843 else if( layers.size() > 3 )
844 {
845 layerDesc.Printf( _( "on %s, %s and %zu more" ),
846 GetBoard()->GetLayerName( layers[0] ),
847 GetBoard()->GetLayerName( layers[1] ),
848 layers.size() - 2 );
849 }
850
851 // Check whether the selected contour is a hole (contour index > 0)
852 if( m_CornerSelection != nullptr && m_CornerSelection->m_contour > 0 )
853 {
854 if( GetIsRuleArea() )
855 return wxString::Format( _( "Rule Area Cutout %s" ), layerDesc );
856 else
857 return wxString::Format( _( "Zone Cutout %s" ), layerDesc );
858 }
859 else
860 {
861 if( GetIsRuleArea() )
862 return wxString::Format( _( "Rule Area %s" ), layerDesc );
863 else
864 return wxString::Format( _( "Zone %s %s" ), GetNetnameMsg(), layerDesc );
865 }
866}
867
868
870{
871 return m_borderHatchPitch;
872}
873
874
876 int aBorderHatchPitch, bool aRebuildBorderHatch )
877{
878 aBorderHatchPitch = std::max( aBorderHatchPitch,
880 aBorderHatchPitch = std::min( aBorderHatchPitch,
882 SetBorderHatchPitch( aBorderHatchPitch );
883 m_borderStyle = aBorderHatchStyle;
884
885 if( aRebuildBorderHatch )
886 HatchBorder();
887}
888
889
891{
892 m_borderHatchPitch = aPitch;
893}
894
895
897{
898 m_borderHatchLines.clear();
899}
900
901
902// Creates hatch lines inside the outline of the complex polygon
903// sort function used in ::HatchBorder to sort points by descending VECTOR2I.x values
904bool sortEndsByDescendingX( const VECTOR2I& ref, const VECTOR2I& tst )
905{
906 return tst.x < ref.x;
907}
908
909
911{
913
914 if( m_borderStyle == ZONE_BORDER_DISPLAY_STYLE::NO_HATCH
915 || m_borderHatchPitch == 0
916 || m_Poly->IsEmpty() )
917 {
918 return;
919 }
920
921 // define range for hatch lines
922 int min_x = m_Poly->CVertex( 0 ).x;
923 int max_x = m_Poly->CVertex( 0 ).x;
924 int min_y = m_Poly->CVertex( 0 ).y;
925 int max_y = m_Poly->CVertex( 0 ).y;
926
927 for( auto iterator = m_Poly->IterateWithHoles(); iterator; iterator++ )
928 {
929 if( iterator->x < min_x )
930 min_x = iterator->x;
931
932 if( iterator->x > max_x )
933 max_x = iterator->x;
934
935 if( iterator->y < min_y )
936 min_y = iterator->y;
937
938 if( iterator->y > max_y )
939 max_y = iterator->y;
940 }
941
942 // Calculate spacing between 2 hatch lines
943 int spacing;
944
945 if( m_borderStyle == ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE )
946 spacing = m_borderHatchPitch;
947 else
948 spacing = m_borderHatchPitch * 2;
949
950 // set the "length" of hatch lines (the length on horizontal axis)
951 int hatch_line_len = m_borderHatchPitch;
952
953 // To have a better look, give a slope depending on the layer
954 int layer = GetFirstLayer();
955 std::vector<int> slope_flags;
956
957 if( IsTeardropArea() )
958 slope_flags = { 1, -1 };
959 else if( layer & 1 )
960 slope_flags = { 1 };
961 else
962 slope_flags = { -1 };
963
964 for( int slope_flag : slope_flags )
965 {
966 double slope = 0.707106 * slope_flag; // 45 degrees slope
967 int64_t max_a, min_a;
968
969 if( slope_flag == 1 )
970 {
971 max_a = KiROUND( max_y - slope * min_x );
972 min_a = KiROUND( min_y - slope * max_x );
973 }
974 else
975 {
976 max_a = KiROUND( max_y - slope * max_x );
977 min_a = KiROUND( min_y - slope * min_x );
978 }
979
980 min_a = (min_a / spacing) * spacing;
981
982 // calculate an offset depending on layer number,
983 // for a better look of hatches on a multilayer board
984 int offset = (layer * 7) / 8;
985 min_a += offset;
986
987 // loop through hatch lines
988 std::vector<VECTOR2I> pointbuffer;
989 pointbuffer.reserve( 256 );
990
991 for( int64_t a = min_a; a < max_a; a += spacing )
992 {
993 pointbuffer.clear();
994
995 // Iterate through all vertices
996 for( auto iterator = m_Poly->IterateSegmentsWithHoles(); iterator; iterator++ )
997 {
998 const SEG seg = *iterator;
999 double x, y;
1000
1001 if( FindLineSegmentIntersection( a, slope, seg.A.x, seg.A.y, seg.B.x, seg.B.y, x, y ) )
1002 pointbuffer.emplace_back( KiROUND( x ), KiROUND( y ) );
1003 }
1004
1005 // sort points in order of descending x (if more than 2) to
1006 // ensure the starting point and the ending point of the same segment
1007 // are stored one just after the other.
1008 if( pointbuffer.size() > 2 )
1009 sort( pointbuffer.begin(), pointbuffer.end(), sortEndsByDescendingX );
1010
1011 // creates lines or short segments inside the complex polygon
1012 for( size_t ip = 0; ip + 1 < pointbuffer.size(); ip += 2 )
1013 {
1014 int dx = pointbuffer[ip + 1].x - pointbuffer[ip].x;
1015
1016 // Push only one line for diagonal hatch,
1017 // or for small lines < twice the line length
1018 // else push 2 small lines
1019 if( m_borderStyle == ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL
1020 || std::abs( dx ) < 2 * hatch_line_len )
1021 {
1022 m_borderHatchLines.emplace_back( SEG( pointbuffer[ip], pointbuffer[ ip + 1] ) );
1023 }
1024 else
1025 {
1026 double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y;
1027 slope = dy / dx;
1028
1029 if( dx > 0 )
1030 dx = hatch_line_len;
1031 else
1032 dx = -hatch_line_len;
1033
1034 int x1 = KiROUND( pointbuffer[ip].x + dx );
1035 int x2 = KiROUND( pointbuffer[ip + 1].x - dx );
1036 int y1 = KiROUND( pointbuffer[ip].y + dx * slope );
1037 int y2 = KiROUND( pointbuffer[ip + 1].y - dx * slope );
1038
1039 m_borderHatchLines.emplace_back( SEG( pointbuffer[ip].x, pointbuffer[ip].y,
1040 x1, y1 ) );
1041
1042 m_borderHatchLines.emplace_back( SEG( pointbuffer[ip+1].x, pointbuffer[ip+1].y,
1043 x2, y2 ) );
1044 }
1045 }
1046 }
1047 }
1048}
1049
1050
1052{
1054}
1055
1056
1058{
1059 return BITMAPS::add_zone;
1060}
1061
1062
1064{
1065 assert( aImage->Type() == PCB_ZONE_T );
1066
1067 std::swap( *static_cast<ZONE*>( this ), *static_cast<ZONE*>( aImage) );
1068}
1069
1070
1072{
1073 if( aLayer == UNDEFINED_LAYER )
1074 {
1075 for( auto& [ layer, poly ] : m_FilledPolysList )
1076 poly->CacheTriangulation();
1077
1078 m_Poly->CacheTriangulation( false );
1079 }
1080 else
1081 {
1082 if( m_FilledPolysList.count( aLayer ) )
1083 m_FilledPolysList[ aLayer ]->CacheTriangulation();
1084 }
1085}
1086
1087
1088bool ZONE::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const
1089{
1090 if( GetNetCode() < 1 )
1091 return true;
1092
1093 if( !m_insulatedIslands.count( aLayer ) )
1094 return false;
1095
1096 return m_insulatedIslands.at( aLayer ).count( aPolyIdx );
1097}
1098
1099
1100void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aSameNetCollidingZones,
1101 std::vector<ZONE*>* aOtherNetIntersectingZones ) const
1102{
1103 int epsilon = pcbIUScale.mmToIU( 0.001 );
1104 BOX2I bbox = GetBoundingBox();
1105
1106 bbox.Inflate( epsilon );
1107
1108 for( ZONE* candidate : GetBoard()->Zones() )
1109 {
1110 if( candidate == this )
1111 continue;
1112
1113 if( !candidate->GetLayerSet().test( aLayer ) )
1114 continue;
1115
1116 if( candidate->GetIsRuleArea() || candidate->IsTeardropArea() )
1117 continue;
1118
1119 if( !candidate->GetBoundingBox().Intersects( bbox ) )
1120 continue;
1121
1122 if( candidate->GetNetCode() == GetNetCode() )
1123 {
1124 if( m_Poly->Collide( candidate->m_Poly ) )
1125 aSameNetCollidingZones->push_back( candidate );
1126 }
1127 else
1128 {
1129 aOtherNetIntersectingZones->push_back( candidate );
1130 }
1131 }
1132}
1133
1134
1136 SHAPE_POLY_SET* aBoardOutline,
1137 SHAPE_POLY_SET* aSmoothedPolyWithApron ) const
1138{
1139 if( GetNumCorners() <= 2 ) // malformed zone. polygon calculations will not like it ...
1140 return false;
1141
1142 // Processing of arc shapes in zones is not yet supported because Clipper can't do boolean
1143 // operations on them. The poly outline must be converted to segments first.
1145 flattened.ClearArcs();
1146
1147 if( GetIsRuleArea() )
1148 {
1149 // We like keepouts just the way they are....
1150 aSmoothedPoly = flattened;
1151 return true;
1152 }
1153
1154 const BOARD* board = GetBoard();
1155 int maxError = ARC_HIGH_DEF;
1156 bool keepExternalFillets = false;
1159
1160 if( IsTeardropArea() )
1161 {
1162 // We use teardrop shapes with no smoothing; these shapes are already optimized
1163 smooth_requested = false;
1164 }
1165
1166 if( board )
1167 {
1169
1170 maxError = bds.m_MaxError;
1171 keepExternalFillets = bds.m_ZoneKeepExternalFillets;
1172 }
1173
1174 auto smooth = [&]( SHAPE_POLY_SET& aPoly )
1175 {
1176 if( !smooth_requested )
1177 return;
1178
1179 switch( m_cornerSmoothingType )
1180 {
1182 aPoly = aPoly.Chamfer( (int) m_cornerRadius );
1183 break;
1184
1186 {
1187 aPoly = aPoly.Fillet( (int) m_cornerRadius, maxError );
1188 break;
1189 }
1190
1191 default:
1192 break;
1193 }
1194 };
1195
1196 SHAPE_POLY_SET* maxExtents = &flattened;
1197 SHAPE_POLY_SET withFillets;
1198
1199 aSmoothedPoly = flattened;
1200
1201 // Should external fillets (that is, those applied to concave corners) be kept? While it
1202 // seems safer to never have copper extend outside the zone outline, 5.1.x and prior did
1203 // indeed fill them so we leave the mode available.
1204 if( keepExternalFillets && smooth_requested )
1205 {
1206 withFillets = flattened;
1207 smooth( withFillets );
1208 withFillets.BooleanAdd( flattened, SHAPE_POLY_SET::PM_FAST );
1209 maxExtents = &withFillets;
1210 }
1211
1212 // We now add in the areas of any same-net, intersecting zones. This keeps us from smoothing
1213 // corners at an intersection (which often produces undesired divots between the intersecting
1214 // zones -- see #2752).
1215 //
1216 // After smoothing, we'll subtract back out everything outside of our zone.
1217 std::vector<ZONE*> sameNetCollidingZones;
1218 std::vector<ZONE*> diffNetIntersectingZones;
1219 GetInteractingZones( aLayer, &sameNetCollidingZones, &diffNetIntersectingZones );
1220
1221 for( ZONE* sameNetZone : sameNetCollidingZones )
1222 {
1223 BOX2I sameNetBoundingBox = sameNetZone->GetBoundingBox();
1224
1225 // Note: a two-pass algorithm could use sameNetZone's actual fill instead of its outline.
1226 // This would obviate the need for the below wrinkles, in addition to fixing both issues
1227 // in #16095.
1228 // (And we wouldn't need to collect all the diffNetIntersectingZones either.)
1229
1230 SHAPE_POLY_SET sameNetPoly = sameNetZone->Outline()->CloneDropTriangulation();
1231 SHAPE_POLY_SET diffNetPoly;
1232
1233 // Of course there's always a wrinkle. The same-net intersecting zone *might* get knocked
1234 // out along the border by a higher-priority, different-net zone. #12797
1235 for( ZONE* diffNetZone : diffNetIntersectingZones )
1236 {
1237 if( diffNetZone->HigherPriority( sameNetZone )
1238 && diffNetZone->GetBoundingBox().Intersects( sameNetBoundingBox ) )
1239 {
1240 diffNetPoly.BooleanAdd( *diffNetZone->Outline(), SHAPE_POLY_SET::PM_FAST );
1241 }
1242 }
1243
1244 // Second wrinkle. After unioning the higher priority, different net zones together, we
1245 // need to check to see if they completely enclose our zone. If they do, then we need to
1246 // treat the enclosed zone as isolated, not connected to the outer zone. #13915
1247 bool isolated = false;
1248
1249 if( diffNetPoly.OutlineCount() )
1250 {
1252
1253 thisPoly.BooleanSubtract( diffNetPoly, SHAPE_POLY_SET::PM_FAST );
1254 isolated = thisPoly.OutlineCount() == 0;
1255 }
1256
1257 if( !isolated )
1258 {
1259 sameNetPoly.ClearArcs();
1260 aSmoothedPoly.BooleanAdd( sameNetPoly, SHAPE_POLY_SET::PM_FAST );
1261 }
1262 }
1263
1264 if( aBoardOutline )
1265 aSmoothedPoly.BooleanIntersection( *aBoardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1266
1267 smooth( aSmoothedPoly );
1268
1269 if( aSmoothedPolyWithApron )
1270 {
1271 SHAPE_POLY_SET poly = maxExtents->CloneDropTriangulation();
1272 poly.Inflate( m_ZoneMinThickness, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
1273 *aSmoothedPolyWithApron = aSmoothedPoly;
1274 aSmoothedPolyWithApron->BooleanIntersection( poly, SHAPE_POLY_SET::PM_FAST );
1275 }
1276
1277 aSmoothedPoly.BooleanIntersection( *maxExtents, SHAPE_POLY_SET::PM_FAST );
1278
1279 return true;
1280}
1281
1282
1284{
1285 m_area = 0.0;
1286
1287 // Iterate over each outline polygon in the zone and then iterate over
1288 // each hole it has to compute the total area.
1289 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1290 {
1291 std::shared_ptr<SHAPE_POLY_SET>& poly = pair.second;
1292
1293 for( int i = 0; i < poly->OutlineCount(); i++ )
1294 {
1295 m_area += poly->Outline( i ).Area();
1296
1297 for( int j = 0; j < poly->HoleCount( i ); j++ )
1298 m_area -= poly->Hole( i, j ).Area();
1299 }
1300 }
1301
1302 return m_area;
1303}
1304
1305
1307{
1309 return m_outlinearea;
1310}
1311
1312
1314 int aMaxError, ERROR_LOC aErrorLoc,
1315 SHAPE_POLY_SET* aBoardOutline ) const
1316{
1317 // Creates the zone outline polygon (with holes if any)
1318 SHAPE_POLY_SET polybuffer;
1319
1320 // TODO: using GetFirstLayer() means it only works for single-layer zones....
1321 BuildSmoothedPoly( polybuffer, GetFirstLayer(), aBoardOutline );
1322
1323 // Calculate the polygon with clearance
1324 // holes are linked to the main outline, so only one polygon is created.
1325 if( aClearance )
1326 {
1327 const BOARD* board = GetBoard();
1328 int maxError = ARC_HIGH_DEF;
1329
1330 if( board )
1331 maxError = board->GetDesignSettings().m_MaxError;
1332
1333 if( aErrorLoc == ERROR_OUTSIDE )
1334 aClearance += maxError;
1335
1336 polybuffer.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
1337 }
1338
1339 polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );
1340 aBuffer.Append( polybuffer );
1341}
1342
1343
1344std::shared_ptr<SHAPE> ZONE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
1345{
1346 if( m_FilledPolysList.find( aLayer ) == m_FilledPolysList.end() )
1347 return std::make_shared<SHAPE_NULL>();
1348 else
1349 return m_FilledPolysList.at( aLayer );
1350}
1351
1352
1353void ZONE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
1354 int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth ) const
1355{
1356 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for zones." ) );
1357
1358 if( !m_FilledPolysList.count( aLayer ) )
1359 return;
1360
1361 if( !aClearance )
1362 {
1363 aBuffer.Append( *m_FilledPolysList.at( aLayer ) );
1364 return;
1365 }
1366
1367 SHAPE_POLY_SET temp_buf = m_FilledPolysList.at( aLayer )->CloneDropTriangulation();
1368
1369 // Rebuild filled areas only if clearance is not 0
1370 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
1371 {
1372 if( aErrorLoc == ERROR_OUTSIDE )
1373 aClearance += aError;
1374
1375 temp_buf.InflateWithLinkedHoles( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aError,
1377 }
1378
1379 aBuffer.Append( temp_buf );
1380}
1381
1382
1384{
1385 if( m_FilledPolysList.count( aLayer ) && !m_FilledPolysList.at( aLayer )->IsEmpty() )
1386 aBuffer.Append( *m_FilledPolysList.at( aLayer ) );
1387}
1388
1389
1390bool ZONE::operator==( const BOARD_ITEM& aOther ) const
1391{
1392 if( aOther.Type() != Type() )
1393 return false;
1394
1395 const ZONE& other = static_cast<const ZONE&>( aOther );
1396 return *this == other;
1397}
1398
1399
1400bool ZONE::operator==( const ZONE& aOther ) const
1401{
1402 if( GetIsRuleArea() != aOther.GetIsRuleArea() )
1403 return false;
1404
1405 if( GetLayerSet() != aOther.GetLayerSet() )
1406 return false;
1407
1408 if( GetNetCode() != aOther.GetNetCode() )
1409 return false;
1410
1411 if( GetIsRuleArea() )
1412 {
1414 return false;
1415 if( GetDoNotAllowTracks() != aOther.GetDoNotAllowTracks() )
1416 return false;
1417 if( GetDoNotAllowVias() != aOther.GetDoNotAllowVias() )
1418 return false;
1420 return false;
1421 if( GetDoNotAllowPads() != aOther.GetDoNotAllowPads() )
1422 return false;
1423 }
1424 else
1425 {
1426 if( GetAssignedPriority() != aOther.GetAssignedPriority() )
1427 return false;
1428
1429 if( GetMinThickness() != aOther.GetMinThickness() )
1430 return false;
1431
1433 return false;
1434
1435 if( GetCornerRadius() != aOther.GetCornerRadius() )
1436 return false;
1437
1438 if( GetTeardropParams() != aOther.GetTeardropParams() )
1439 return false;
1440 }
1441
1442 if( GetNumCorners() != aOther.GetNumCorners() )
1443 return false;
1444
1445 for( int ii = 0; ii < GetNumCorners(); ii++ )
1446 {
1447 if( GetCornerPosition( ii ) != aOther.GetCornerPosition( ii ) )
1448 return false;
1449 }
1450
1451 return true;
1452}
1453
1454
1455double ZONE::Similarity( const BOARD_ITEM& aOther ) const
1456{
1457 if( aOther.Type() != Type() )
1458 return 0.0;
1459
1460 const ZONE& other = static_cast<const ZONE&>( aOther );
1461
1462 if( GetIsRuleArea() != other.GetIsRuleArea() )
1463 return 0.0;
1464
1465 double similarity = 1.0;
1466
1467 if( GetLayerSet() != other.GetLayerSet() )
1468 similarity *= 0.9;
1469
1470 if( GetNetCode() != other.GetNetCode() )
1471 similarity *= 0.9;
1472
1473 if( !GetIsRuleArea() )
1474 {
1475 if( GetAssignedPriority() != other.GetAssignedPriority() )
1476 similarity *= 0.9;
1477
1478 if( GetMinThickness() != other.GetMinThickness() )
1479 similarity *= 0.9;
1480
1482 similarity *= 0.9;
1483
1484 if( GetCornerRadius() != other.GetCornerRadius() )
1485 similarity *= 0.9;
1486
1487 if( GetTeardropParams() != other.GetTeardropParams() )
1488 similarity *= 0.9;
1489 }
1490 else
1491 {
1493 similarity *= 0.9;
1494 if( GetDoNotAllowTracks() != other.GetDoNotAllowTracks() )
1495 similarity *= 0.9;
1496 if( GetDoNotAllowVias() != other.GetDoNotAllowVias() )
1497 similarity *= 0.9;
1499 similarity *= 0.9;
1500 if( GetDoNotAllowPads() != other.GetDoNotAllowPads() )
1501 similarity *= 0.9;
1502 }
1503
1504 std::vector<VECTOR2I> corners;
1505 std::vector<VECTOR2I> otherCorners;
1506 VECTOR2I lastCorner( 0, 0 );
1507
1508 for( int ii = 0; ii < GetNumCorners(); ii++ )
1509 {
1510 corners.push_back( lastCorner - GetCornerPosition( ii ) );
1511 lastCorner = GetCornerPosition( ii );
1512 }
1513
1514 lastCorner = VECTOR2I( 0, 0 );
1515 for( int ii = 0; ii < other.GetNumCorners(); ii++ )
1516 {
1517 otherCorners.push_back( lastCorner - other.GetCornerPosition( ii ) );
1518 lastCorner = other.GetCornerPosition( ii );
1519 }
1520
1521 size_t longest = alg::longest_common_subset( corners, otherCorners );
1522
1523 similarity *= std::pow( 0.9, GetNumCorners() + other.GetNumCorners() - 2 * longest );
1524
1525 return similarity;
1526}
1527
1528
1529static struct ZONE_DESC
1530{
1532 {
1534
1535 if( layerEnum.Choices().GetCount() == 0 )
1536 {
1537 layerEnum.Undefined( UNDEFINED_LAYER );
1538
1539 for( LSEQ seq = LSET::AllLayersMask().Seq(); seq; ++seq )
1540 layerEnum.Map( *seq, LSET::Name( *seq ) );
1541 }
1542
1544
1545 if( zcMap.Choices().GetCount() == 0 )
1546 {
1547 zcMap.Undefined( ZONE_CONNECTION::INHERITED );
1548 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
1549 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
1550 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
1551 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
1552 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
1553 }
1554
1556
1557 if( zfmMap.Choices().GetCount() == 0 )
1558 {
1559 zfmMap.Undefined( ZONE_FILL_MODE::POLYGONS );
1560 zfmMap.Map( ZONE_FILL_MODE::POLYGONS, _HKI( "Solid fill" ) )
1561 .Map( ZONE_FILL_MODE::HATCH_PATTERN, _HKI( "Hatch pattern" ) );
1562 }
1563
1565
1566 if( irmMap.Choices().GetCount() == 0 )
1567 {
1568 irmMap.Undefined( ISLAND_REMOVAL_MODE::ALWAYS );
1569 irmMap.Map( ISLAND_REMOVAL_MODE::ALWAYS, _HKI( "Always" ) )
1570 .Map( ISLAND_REMOVAL_MODE::NEVER, _HKI( "Never" ) )
1571 .Map( ISLAND_REMOVAL_MODE::AREA, _HKI( "Below area limit" ) );
1572 }
1573
1577
1578 // Mask layer and position properties; they aren't useful in current form
1579 auto posX = new PROPERTY<ZONE, int>( _HKI( "Position X" ), NO_SETTER( ZONE, int ),
1580 static_cast<int ( ZONE::* )() const>( &ZONE::GetX ),
1581 PROPERTY_DISPLAY::PT_COORD,
1583 posX->SetIsHiddenFromPropertiesManager();
1584
1585 auto posY = new PROPERTY<ZONE, int>( _HKI( "Position Y" ), NO_SETTER( ZONE, int ),
1586 static_cast<int ( ZONE::* )() const>( &ZONE::GetY ),
1587 PROPERTY_DISPLAY::PT_COORD,
1589 posY->SetIsHiddenFromPropertiesManager();
1590
1591 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ), posX );
1592 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ), posY );
1593
1594 auto isCopperZone =
1595 []( INSPECTABLE* aItem ) -> bool
1596 {
1597 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
1598 return !zone->GetIsRuleArea() && IsCopperLayer( zone->GetFirstLayer() );
1599
1600 return false;
1601 };
1602
1603 auto isHatchedFill =
1604 []( INSPECTABLE* aItem ) -> bool
1605 {
1606 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
1607 return zone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN;
1608
1609 return false;
1610 };
1611
1612 auto isAreaBasedIslandRemoval =
1613 []( INSPECTABLE* aItem ) -> bool
1614 {
1615 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
1616 return zone->GetIslandRemovalMode() == ISLAND_REMOVAL_MODE::AREA;
1617
1618 return false;
1619 };
1620
1621 // Layer property is hidden because it only holds a single layer and zones actually use
1622 // a layer set
1623 propMgr.ReplaceProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ),
1626 &ZONE::GetLayer ) )
1627 .SetIsHiddenFromPropertiesManager();
1628
1630 _HKI( "Net" ), isCopperZone );
1632 _HKI( "Net Class" ), isCopperZone );
1633
1634 propMgr.AddProperty( new PROPERTY<ZONE, unsigned>( _HKI( "Priority" ),
1636 .SetAvailableFunc( isCopperZone );
1637
1638 propMgr.AddProperty( new PROPERTY<ZONE, wxString>( _HKI( "Name" ),
1640
1641 const wxString groupFill = _HKI( "Fill Style" );
1642
1643 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ZONE_FILL_MODE>( _HKI( "Fill Mode" ),
1645 groupFill )
1646 .SetAvailableFunc( isCopperZone );
1647
1648 propMgr.AddProperty( new PROPERTY<ZONE, EDA_ANGLE>( _HKI( "Orientation" ),
1650 PROPERTY_DISPLAY::PT_DEGREE ),
1651 groupFill )
1652 .SetAvailableFunc( isCopperZone )
1653 .SetWriteableFunc( isHatchedFill );
1654
1655 auto atLeastMinWidthValidator =
1656 []( const wxAny&& aValue, EDA_ITEM* aZone ) -> VALIDATOR_RESULT
1657 {
1658 int val = aValue.As<int>();
1659 ZONE* zone = dynamic_cast<ZONE*>( aZone );
1660 wxCHECK( zone, std::nullopt );
1661
1662 if( val < zone->GetMinThickness() )
1663 {
1664 return std::make_unique<VALIDATION_ERROR_MSG>(
1665 _( "Cannot be less than zone minimum width" ) );
1666 }
1667
1668 return std::nullopt;
1669 };
1670
1671 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Hatch Width" ),
1672 &ZONE::SetHatchThickness, &ZONE::GetHatchThickness, PROPERTY_DISPLAY::PT_SIZE ),
1673 groupFill )
1674 .SetAvailableFunc( isCopperZone )
1675 .SetWriteableFunc( isHatchedFill )
1676 .SetValidator( atLeastMinWidthValidator );
1677
1678 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Hatch Gap" ),
1679 &ZONE::SetHatchGap, &ZONE::GetHatchGap, PROPERTY_DISPLAY::PT_SIZE ),
1680 groupFill )
1681 .SetAvailableFunc( isCopperZone )
1682 .SetWriteableFunc( isHatchedFill )
1683 .SetValidator( atLeastMinWidthValidator );
1684
1685 propMgr.AddProperty( new PROPERTY<ZONE, double>( _HKI( "Hatch Minimum Hole Ratio" ),
1687 groupFill )
1688 .SetAvailableFunc( isCopperZone )
1689 .SetWriteableFunc( isHatchedFill )
1691
1692 // TODO: Smoothing effort needs to change to enum (in dialog too)
1693 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Smoothing Effort" ),
1695 groupFill )
1696 .SetAvailableFunc( isCopperZone )
1697 .SetWriteableFunc( isHatchedFill );
1698
1699 propMgr.AddProperty( new PROPERTY<ZONE, double>( _HKI( "Smoothing Amount" ),
1701 groupFill )
1702 .SetAvailableFunc( isCopperZone )
1703 .SetWriteableFunc( isHatchedFill );
1704
1705 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ISLAND_REMOVAL_MODE>( _HKI( "Remove Islands" ),
1707 groupFill )
1708 .SetAvailableFunc( isCopperZone );
1709
1710 propMgr.AddProperty( new PROPERTY<ZONE, long long int>( _HKI( "Minimum Island Area" ),
1711 &ZONE::SetMinIslandArea, &ZONE::GetMinIslandArea, PROPERTY_DISPLAY::PT_AREA ),
1712 groupFill )
1713 .SetAvailableFunc( isCopperZone )
1714 .SetWriteableFunc( isAreaBasedIslandRemoval );
1715
1716 const wxString groupElectrical = _HKI( "Electrical" );
1717
1718 auto clearanceOverride = new PROPERTY<ZONE, std::optional<int>>( _HKI( "Clearance" ),
1720 PROPERTY_DISPLAY::PT_SIZE );
1721 clearanceOverride->SetAvailableFunc( isCopperZone );
1722 constexpr int maxClearance = pcbIUScale.mmToIU( ZONE_CLEARANCE_MAX_VALUE_MM );
1723 clearanceOverride->SetValidator( PROPERTY_VALIDATORS::RangeIntValidator<0, maxClearance> );
1724
1725 auto minWidth = new PROPERTY<ZONE, int>( _HKI( "Minimum Width" ),
1727 PROPERTY_DISPLAY::PT_SIZE );
1728 minWidth->SetAvailableFunc( isCopperZone );
1729 constexpr int minMinWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
1730 clearanceOverride->SetValidator( PROPERTY_VALIDATORS::RangeIntValidator<minMinWidth,
1731 INT_MAX> );
1732
1733 auto padConnections = new PROPERTY_ENUM<ZONE, ZONE_CONNECTION>( _HKI( "Pad Connections" ),
1735 padConnections->SetAvailableFunc( isCopperZone );
1736
1737 auto thermalGap = new PROPERTY<ZONE, int>( _HKI( "Thermal Relief Gap" ),
1739 PROPERTY_DISPLAY::PT_SIZE );
1740 thermalGap->SetAvailableFunc( isCopperZone );
1741 thermalGap->SetValidator( PROPERTY_VALIDATORS::PositiveIntValidator );
1742
1743 auto thermalSpokeWidth = new PROPERTY<ZONE, int>( _HKI( "Thermal Relief Spoke Width" ),
1745 PROPERTY_DISPLAY::PT_SIZE );
1746 thermalSpokeWidth->SetAvailableFunc( isCopperZone );
1747 thermalSpokeWidth->SetValidator( atLeastMinWidthValidator );
1748
1749 propMgr.AddProperty( clearanceOverride, groupElectrical );
1750 propMgr.AddProperty( minWidth, groupElectrical );
1751 propMgr.AddProperty( padConnections, groupElectrical );
1752 propMgr.AddProperty( thermalGap, groupElectrical );
1753 propMgr.AddProperty( thermalSpokeWidth, groupElectrical );
1754 }
1756
constexpr int ARC_HIGH_DEF
Definition: base_units.h:120
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
wxString GetNetnameMsg() const
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
NETINFO_ITEM * m_netinfo
Store all information about the net that item belongs to.
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
TEARDROP_PARAMETERS & GetTeardropParams()
Container for design settings for a BOARD object.
ZONE_SETTINGS & GetDefaultZoneSettings()
Abstract interface for BOARD_ITEMs capable of storing other items inside.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
int GetY() const
Definition: board_item.h:101
int GetX() const
Definition: board_item.h:95
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:248
virtual bool IsLocked() const
Definition: board_item.cpp:74
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
Definition: board_item.cpp:103
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:282
std::unordered_map< const ZONE *, BOX2I > m_ZoneBBoxCache
Definition: board.h:1269
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:794
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:136
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:294
bool Contains(const Vec &aPoint) const
Definition: box2.h:158
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:541
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition: eda_item.cpp:258
const KIID m_Uuid
Definition: eda_item.h:485
bool m_forceVisible
Definition: eda_item.h:489
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:490
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:130
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:669
static ENUM_MAP< T > & Instance()
Definition: property.h:663
ENUM_MAP & Undefined(T aValue)
Definition: property.h:676
wxPGChoices & Choices()
Definition: property.h:712
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:36
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:68
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:412
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Definition: layer_ids.h:522
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:576
LSEQ UIOrder() const
Definition: lset.cpp:1012
static LSET AllLayersMask()
Definition: lset.cpp:898
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:418
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:863
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition: lset.cpp:89
Definition: pad.h:53
int GetLocalThermalGapOverride(wxString *aSource=nullptr) const
Definition: pad.cpp:1114
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:257
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition: property.h:268
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition: property.h:330
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:85
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:87
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
void OverrideAvailability(TYPE_ID aDerived, TYPE_ID aBase, const wxString &aName, std::function< bool(INSPECTABLE *)> aFunc)
Sets an override availability functor for a base class property of a given derived class.
PROPERTY_BASE & ReplaceProperty(size_t aBase, const wxString &aName, PROPERTY_BASE *aNew, const wxString &aGroup=wxEmptyString)
Replace an existing property for a specific type.
static VALIDATOR_RESULT PositiveRatioValidator(const wxAny &&aValue, EDA_ITEM *aItem)
static VALIDATOR_RESULT PositiveIntValidator(const wxAny &&aValue, EDA_ITEM *aItem)
static VALIDATOR_RESULT RangeIntValidator(const wxAny &&aValue, EDA_ITEM *aItem)
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
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...
bool IsClosed() const override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
Represent a set of closed polygons.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
bool CollideEdge(const VECTOR2I &aPoint, VERTEX_INDEX *aClosestVertex=nullptr, int aClearance=0) const
Check whether aPoint collides with any edge of any of the contours of the polygon.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
void InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError, POLYGON_MODE aFastMode)
Perform outline inflation/deflation, using round corners.
ITERATOR IterateWithHoles(int aOutline)
void Fracture(POLYGON_MODE aFastMode)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
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.
double Area()
Return the area of this poly set.
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
bool IsEmpty() const
Return true if the set is empty (no polygons at all)
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union For aFastMode meaning, see function booleanOp.
bool Collide(const SHAPE *aShape, int aClearance=0, int *aActual=nullptr, VECTOR2I *aLocation=nullptr) const override
Check if the boundary of shape (this) lies closer to the shape aShape than aClearance,...
int TotalVertices() const
Return total number of vertices stored in the set.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset intersection For aFastMode meaning, see function booleanOp.
MD5_HASH GetHash() const
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
int HoleCount(int aOutline) const
Returns the number of holes in a given outline.
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Appends a vertex at the end of the given outline/hole (default: the last outline)
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Adds a new hole to the given outline (default: last) and returns its index.
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
bool GetNeighbourIndexes(int aGlobalIndex, int *aPrevious, int *aNext) const
Return the global indexes of the previous and the next corner of the aGlobalIndex-th corner of a cont...
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the reference to aHole-th hole in the aIndex-th outline.
int NewOutline()
Creates a new empty polygon in the set and returns its index.
bool CollideVertex(const VECTOR2I &aPoint, VERTEX_INDEX *aClosestVertex=nullptr, int aClearance=0) const
Check whether aPoint collides with any vertex of any of the contours of the polygon.
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the index-th vertex in a given hole outline within a given outline.
int OutlineCount() const
Return the number of outlines in the set.
void Move(const VECTOR2I &aVector) override
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
SHAPE_POLY_SET CloneDropTriangulation() const
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Returns an iterator object, for all outlines in the set (with holes)
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
ZONE_SETTINGS handles zones parameters.
Definition: zone_settings.h:71
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
void SetHatchThickness(int aThickness)
Definition: zone.h:285
SHAPE_POLY_SET::VERTEX_INDEX * m_CornerSelection
The index of the corner being moved or nullptr if no corner is selected.
Definition: zone.h:889
void SetNeedRefill(bool aNeedRefill)
Definition: zone.h:264
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if a point is near an outline edge or a corner of this zone.
Definition: zone.cpp:425
int m_borderHatchPitch
Definition: zone.h:910
bool m_isRuleArea
Definition: zone.h:825
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
Definition: zone.cpp:821
ZONE & operator=(const ZONE &aOther)
Definition: zone.cpp:80
int m_cornerSmoothingType
Definition: zone.h:808
void Mirror(const VECTOR2I &aMirrorRef, bool aMirrorLeftRight)
Mirror the outlines relative to a given horizontal axis the layer is not changed.
Definition: zone.cpp:744
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:710
std::optional< int > GetLocalClearance() const override
Definition: zone.cpp:490
void SetLocalClearance(std::optional< int > aClearance)
Definition: zone.h:154
bool m_doNotAllowVias
Definition: zone.h:837
bool UnFill()
Removes the zone filling.
Definition: zone.cpp:207
bool GetDoNotAllowVias() const
Definition: zone.h:712
void TransformSolidAreasShapesToPolygon(PCB_LAYER_ID aLayer, SHAPE_POLY_SET &aBuffer) const
Convert solid areas full shapes to polygon set (the full shape is the polygon area with a thick outli...
Definition: zone.cpp:1383
void SetCornerRadius(unsigned int aRadius)
Definition: zone.cpp:395
ZONE_FILL_MODE m_fillMode
How to fill areas:
Definition: zone.h:875
bool m_doNotAllowFootprints
Definition: zone.h:840
int m_ZoneMinThickness
Definition: zone.h:844
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
Definition: zone.cpp:294
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition: zone.cpp:784
double m_hatchSmoothingValue
Definition: zone.h:883
void SetLocalFlags(int aFlags)
Definition: zone.h:334
void TransformSmoothedOutlineToPolygon(SHAPE_POLY_SET &aBuffer, int aClearance, int aError, ERROR_LOC aErrorLoc, SHAPE_POLY_SET *aBoardOutline) const
Convert the outlines shape to a polygon with no holes inflated (optional) by max( aClearanceValue,...
Definition: zone.cpp:1313
int m_thermalReliefSpokeWidth
Definition: zone.h:866
bool HitTestCutout(const VECTOR2I &aRefPos, int *aOutlineIdx=nullptr, int *aHoleIdx=nullptr) const
Test if the given point is contained within a cutout of the zone.
Definition: zone.cpp:510
EDA_ANGLE m_hatchOrientation
Definition: zone.h:878
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
Definition: zone.cpp:1071
std::map< PCB_LAYER_ID, std::set< int > > m_insulatedIslands
For each layer, a set of insulated islands that were not removed.
Definition: zone.h:914
wxString m_zoneName
An optional unique name for this zone, used for identifying it in DRC checking.
Definition: zone.h:812
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition: zone.cpp:910
std::map< PCB_LAYER_ID, std::shared_ptr< SHAPE_POLY_SET > > m_FilledPolysList
Definition: zone.h:901
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuilBorderdHatch)
Set all hatch parameters for the zone.
Definition: zone.cpp:875
MD5_HASH GetHashValue(PCB_LAYER_ID aLayer)
Definition: zone.cpp:407
bool GetDoNotAllowPads() const
Definition: zone.h:714
const BOX2I GetBoundingBox() const override
Definition: zone.cpp:343
void SetMinThickness(int aMinThickness)
Definition: zone.h:270
double m_outlinearea
Definition: zone.h:917
wxString GetFriendlyName() const override
Definition: zone.cpp:684
bool GetDoNotAllowTracks() const
Definition: zone.h:713
int GetLocalFlags() const
Definition: zone.h:333
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: zone.cpp:178
void SetHatchOrientation(const EDA_ANGLE &aStep)
Definition: zone.h:291
bool m_doNotAllowCopperPour
Definition: zone.h:836
void SetHatchSmoothingValue(double aValue)
Definition: zone.h:297
bool m_needRefill
False when a zone was refilled, true after changes in zone params.
Definition: zone.h:863
virtual void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: zone.cpp:723
bool HitTestForCorner(const VECTOR2I &refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX *aCornerHit=nullptr) const
Test if the given VECTOR2I is near a corner.
Definition: zone.cpp:435
void SetHatchSmoothingLevel(int aLevel)
Definition: zone.h:294
bool m_doNotAllowTracks
Definition: zone.h:838
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
Definition: zone.h:205
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: zone.cpp:237
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:261
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition: zone.h:724
LSET m_fillFlags
Temp variables used while filling.
Definition: zone.h:904
SHAPE_POLY_SET * Outline()
Definition: zone.h:336
bool m_doNotAllowPads
Definition: zone.h:839
ZONE(BOARD_ITEM_CONTAINER *parent)
Definition: zone.cpp:46
void Move(const VECTOR2I &offset) override
Move the outlines.
Definition: zone.cpp:657
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
Definition: zone.cpp:1088
SHAPE_POLY_SET * m_Poly
Outline of the zone.
Definition: zone.h:807
TEARDROP_TYPE m_teardropType
Definition: zone.h:831
~ZONE()
Definition: zone.cpp:90
long long int GetMinIslandArea() const
Definition: zone.h:727
int m_hatchSmoothingLevel
Definition: zone.h:879
double Similarity(const BOARD_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
Definition: zone.cpp:1455
LSET m_layerSet
Definition: zone.h:814
void SetIsRuleArea(bool aEnable)
Definition: zone.h:717
int m_ZoneClearance
Definition: zone.h:843
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
Definition: zone.h:636
const wxString & GetZoneName() const
Definition: zone.h:131
void CacheBoundingBox()
Used to preload the zone bounding box cache so we don't have to worry about mutex-locking it each tim...
Definition: zone.cpp:372
int GetMinThickness() const
Definition: zone.h:269
virtual void swapData(BOARD_ITEM *aImage) override
Definition: zone.cpp:1063
bool HitTestForEdge(const VECTOR2I &refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX *aCornerHit=nullptr) const
Test if the given VECTOR2I is near a segment defined by 2 corners.
Definition: zone.cpp:442
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
Definition: zone.cpp:755
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Rotate the outlines.
Definition: zone.cpp:712
bool HigherPriority(const ZONE *aOther) const
Definition: zone.cpp:184
bool HitTestFilledArea(PCB_LAYER_ID aLayer, const VECTOR2I &aRefPos, int aAccuracy=0) const
Test if the given VECTOR2I is within the bounds of a filled area of this zone.
Definition: zone.cpp:496
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition: zone.h:191
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: zone.cpp:1057
int m_hatchGap
Definition: zone.h:877
ZONE_CONNECTION GetPadConnection() const
Definition: zone.h:266
void InitDataFromSrcInCopyCtor(const ZONE &aZone)
Copy aZone data to me.
Definition: zone.cpp:100
int GetHatchThickness() const
Definition: zone.h:284
double GetHatchHoleMinArea() const
Definition: zone.h:299
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Definition: zone.cpp:535
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:337
int m_hatchBorderAlgorithm
Definition: zone.h:885
bool IsTeardropArea() const
Definition: zone.h:694
std::vector< SEG > m_borderHatchLines
Definition: zone.h:911
VECTOR2I GetPosition() const override
Definition: zone.cpp:231
int GetThermalReliefSpokeWidth() const
Definition: zone.h:213
int GetBorderHatchPitch() const
HatchBorder related methods.
Definition: zone.cpp:869
void BuildHashValue(PCB_LAYER_ID aLayer)
Build the hash value of m_FilledPolysList, and store it internally in m_filledPolysHash.
Definition: zone.cpp:416
void SetThermalReliefGap(int aThermalReliefGap)
Definition: zone.h:194
EDA_ANGLE GetHatchOrientation() const
Definition: zone.h:290
void SetLayerSet(LSET aLayerSet) override
Definition: zone.cpp:267
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
Definition: zone.cpp:1135
int m_fillVersion
Definition: zone.h:845
const VECTOR2I & GetCornerPosition(int aCornerIndex) const
Definition: zone.h:554
bool GetDoNotAllowFootprints() const
Definition: zone.h:715
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:192
double m_hatchHoleMinArea
Definition: zone.h:884
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.h:129
bool GetDoNotAllowCopperPour() const
Definition: zone.h:711
void SetBorderHatchPitch(int aPitch)
Set the hatch pitch parameter for the zone.
Definition: zone.cpp:890
void GetInteractingZones(PCB_LAYER_ID aLayer, std::vector< ZONE * > *aSameNetCollidingZones, std::vector< ZONE * > *aOtherNetIntersectingZones) const
Some intersecting zones, despite being on the same layer with the same net, cannot be merged due to o...
Definition: zone.cpp:1100
int GetHatchGap() const
Definition: zone.h:287
double CalculateOutlineArea()
Compute the area of the zone outline (not the filled area).
Definition: zone.cpp:1306
void SetHatchHoleMinArea(double aPct)
Definition: zone.h:300
unsigned m_priority
Definition: zone.h:820
bool IsConflicting() const
For rule areas which exclude footprints (and therefore participate in courtyard conflicts during move...
Definition: zone.cpp:225
std::map< PCB_LAYER_ID, MD5_HASH > m_filledPolysHash
A hash value used in zone filling calculations to see if the filled areas are up to date.
Definition: zone.h:907
ISLAND_REMOVAL_MODE m_islandRemovalMode
Definition: zone.h:847
bool m_isFilled
True when a zone was filled, false after deleting the filled areas.
Definition: zone.h:856
double GetHatchSmoothingValue() const
Definition: zone.h:296
bool AppendCorner(VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition: zone.cpp:801
void MoveEdge(const VECTOR2I &offset, int aEdge)
Move the outline Edge.
Definition: zone.cpp:697
int GetHatchSmoothingLevel() const
Definition: zone.h:293
unsigned int GetCornerRadius() const
Definition: zone.h:665
int GetCornerSmoothingType() const
Definition: zone.h:661
int m_thermalReliefGap
Definition: zone.h:865
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: zone.cpp:310
bool IsOnCopperLayer() const override
Definition: zone.cpp:255
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
Definition: zone.cpp:1283
int m_hatchThickness
Definition: zone.h:876
void TransformShapeToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, int aClearance, int aError, ERROR_LOC aErrorLoc, bool ignoreLineWidth=false) const override
Convert the zone shape to a closed polygon Used in filling zones calculations Circles and arcs are ap...
Definition: zone.cpp:1353
void SetAssignedPriority(unsigned aPriority)
Definition: zone.h:114
double m_area
Definition: zone.h:916
unsigned int m_cornerRadius
Definition: zone.h:809
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition: zone.h:267
void SetZoneName(const wxString &aName)
Definition: zone.h:132
bool operator==(const ZONE &aOther) const
Definition: zone.cpp:1400
void UnHatchBorder()
Clear the zone's hatch.
Definition: zone.cpp:896
void SetIslandRemovalMode(ISLAND_REMOVAL_MODE aRemove)
Definition: zone.h:725
PCB_LAYER_ID GetFirstLayer() const
Definition: zone.cpp:246
void SetMinIslandArea(long long int aArea)
Definition: zone.h:728
ZONE_CONNECTION m_PadConnection
Definition: zone.h:842
int GetThermalReliefGap() const
Definition: zone.h:202
void SetHatchGap(int aStep)
Definition: zone.h:288
static int GetDefaultHatchPitch()
Definition: zone.cpp:1051
unsigned GetAssignedPriority() const
Definition: zone.h:119
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition: zone.h:514
bool SameNet(const ZONE *aOther) const
Definition: zone.cpp:201
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: zone.cpp:1344
ZONE_BORDER_DISPLAY_STYLE m_borderStyle
Definition: zone.h:909
long long int m_minIslandArea
When island removal mode is set to AREA, islands below this area will be removed.
Definition: zone.h:853
#define _HKI(x)
#define _(s)
#define PCB_EDIT_FRAME_NAME
#define COURTYARD_CONFLICT
temporary set when moving footprints having courtyard overlapping
a few functions useful in geometry calculations.
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_OUTSIDE
Some functions to handle hotkeys in KiCad.
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition: layer_ids.h:149
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:882
@ LAYER_CONFLICTS_SHADOW
shadow layer for items flagged conficting
Definition: layer_ids.h:245
@ LAYER_FOOTPRINTS_FR
show footprints on front
Definition: layer_ids.h:212
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:235
@ LAYER_ZONE_START
Virtual layers for stacking zones and tracks on a given copper layer.
Definition: layer_ids.h:257
@ LAYER_FOOTPRINTS_BK
show footprints on back
Definition: layer_ids.h:213
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:95
@ UNDEFINED_LAYER
Definition: layer_ids.h:61
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint.
Definition: lset.cpp:680
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:634
size_t longest_common_subset(const _Container &__c1, const _Container &__c2)
Returns the length of the longest common subset of values between two containers.
Definition: kicad_algo.h:214
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:390
#define TYPE_HASH(x)
Definition: property.h:71
#define IMPLEMENT_ENUM_TO_WXANY(type)
Definition: property.h:763
#define NO_SETTER(owner, type)
Definition: property.h:774
#define REGISTER_TYPE(x)
Definition: property_mgr.h:371
std::optional< std::unique_ptr< VALIDATION_ERROR > > VALIDATOR_RESULT
Null optional means validation succeeded.
const double epsilon
wxString UnescapeString(const wxString &aSource)
void AccumulateDescription(wxString &aDesc, const wxString &aItem)
Utility to build comma separated lists in messages.
Definition: string_utils.h:336
constexpr int mmToIU(double mm) const
Definition: base_units.h:88
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
ZONE_DESC()
Definition: zone.cpp:1531
TEARDROP_TYPE
define the type of a teardrop: on a via or pad, or a track end
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition: typeinfo.h:107
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:118
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:638
static SHAPE_POLY_SET g_nullPoly
Definition: zone.cpp:404
bool sortEndsByDescendingX(const VECTOR2I &ref, const VECTOR2I &tst)
Definition: zone.cpp:904
static struct ZONE_DESC _ZONE_DESC
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
Definition: zone_settings.h:58
ZONE_FILL_MODE
Definition: zone_settings.h:41
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.
Definition: zone_settings.h:49
#define ZONE_CLEARANCE_MAX_VALUE_MM
Definition: zones.h:38
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:47
#define ZONE_BORDER_HATCH_DIST_MM
Definition: zones.h:39
#define ZONE_BORDER_HATCH_MINDIST_MM
Definition: zones.h:40
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition: zones.h:36
#define ZONE_BORDER_HATCH_MAXDIST_MM
Definition: zones.h:41