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-2023 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
44
47 m_Poly( nullptr ),
48 m_teardropType( TEARDROP_TYPE::TD_NONE ),
49 m_isFilled( false ),
50 m_CornerSelection( nullptr ),
51 m_area( 0.0 ),
52 m_outlinearea( 0.0 )
53{
54 m_Poly = new SHAPE_POLY_SET(); // Outlines
55 SetLocalFlags( 0 ); // flags temporary used in zone calculations
56 m_fillVersion = 5; // set the "old" way to build filled polygon areas (< 6.0.x)
57
58 if( GetParentFootprint() )
59 SetIsRuleArea( true ); // Zones living in footprints have the rule area option
60
61 if( aParent->GetBoard() )
63 else
65
66 m_needRefill = false; // True only after edits.
67}
68
69
70ZONE::ZONE( const ZONE& aZone ) :
71 BOARD_CONNECTED_ITEM( aZone ),
72 m_Poly( nullptr ),
73 m_CornerSelection( nullptr )
74{
76}
77
78
79ZONE& ZONE::operator=( const ZONE& aOther )
80{
82
84
85 return *this;
86}
87
88
90{
91 delete m_Poly;
92 delete m_CornerSelection;
93
94 if( BOARD* board = GetBoard() )
95 board->IncrementTimeStamp();
96}
97
98
100{
101 // members are expected non initialize in this.
102 // InitDataFromSrcInCopyCtor() is expected to be called only from a copy constructor.
103
104 // Copy only useful EDA_ITEM flags:
105 m_flags = aZone.m_flags;
107
108 // Replace the outlines for aZone outlines.
109 delete m_Poly;
110 m_Poly = new SHAPE_POLY_SET( *aZone.m_Poly );
111
114 m_zoneName = aZone.m_zoneName;
115 m_priority = aZone.m_priority;
117 SetLayerSet( aZone.GetLayerSet() );
118
124
126 m_ZoneClearance = aZone.m_ZoneClearance; // clearance value
131
132 m_isFilled = aZone.m_isFilled;
135
138
139 m_fillMode = aZone.m_fillMode; // solid vs. hatched
141 m_hatchGap = aZone.m_hatchGap;
147
148 // For corner moving, corner index to drag, or nullptr if no selection
149 delete m_CornerSelection;
150 m_CornerSelection = nullptr;
151
152 for( PCB_LAYER_ID layer : aZone.GetLayerSet().Seq() )
153 {
154 std::shared_ptr<SHAPE_POLY_SET> fill = aZone.m_FilledPolysList.at( layer );
155
156 if( fill )
157 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>( *fill );
158 else
159 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
160
161 m_filledPolysHash[layer] = aZone.m_filledPolysHash.at( layer );
162 m_insulatedIslands[layer] = aZone.m_insulatedIslands.at( layer );
163 }
164
168
169 SetLocalFlags( aZone.GetLocalFlags() );
170
171 m_netinfo = aZone.m_netinfo;
172 m_area = aZone.m_area;
174}
175
176
178{
179 return new ZONE( *this );
180}
181
182
183bool ZONE::HigherPriority( const ZONE* aOther ) const
184{
185 // Teardrops are always higher priority than regular zones, so if one zone is a teardrop
186 // and the other is not, then return higher priority as the teardrop
187 if( ( m_teardropType == TEARDROP_TYPE::TD_NONE )
188 ^ ( aOther->m_teardropType == TEARDROP_TYPE::TD_NONE ) )
189 {
190 return static_cast<int>( m_teardropType ) > static_cast<int>( aOther->m_teardropType );
191 }
192
193 if( m_priority != aOther->m_priority )
194 return m_priority > aOther->m_priority;
195
196 return m_Uuid > aOther->m_Uuid;
197}
198
199
200bool ZONE::SameNet( const ZONE* aOther ) const
201{
202 return GetNetCode() == aOther->GetNetCode();
203}
204
205
207{
208 bool change = false;
209
210 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
211 {
212 change |= !pair.second->IsEmpty();
213 m_insulatedIslands[pair.first].clear();
214 pair.second->RemoveAllContours();
215 }
216
217 m_isFilled = false;
218 m_fillFlags.reset();
219
220 return change;
221}
222
223
225{
226 return HasFlag( COURTYARD_CONFLICT );
227}
228
229
231{
232 return GetCornerPosition( 0 );
233}
234
235
237{
238 if( m_layerSet.count() == 1 )
239 return m_layerSet.UIOrder()[0];
240 else
241 return UNDEFINED_LAYER;
242}
243
244
246{
247 if( m_layerSet.count() )
248 return m_layerSet.UIOrder()[0];
249 else
250 return UNDEFINED_LAYER;
251}
252
253
255{
256 return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
257}
258
259
261{
262 SetLayerSet( LSET( aLayer ) );
263}
264
265
266void ZONE::SetLayerSet( LSET aLayerSet )
267{
268 if( aLayerSet.count() == 0 )
269 return;
270
271 if( m_layerSet != aLayerSet )
272 {
273 SetNeedRefill( true );
274
275 UnFill();
276
277 m_FilledPolysList.clear();
278 m_filledPolysHash.clear();
279 m_insulatedIslands.clear();
280
281 for( PCB_LAYER_ID layer : aLayerSet.Seq() )
282 {
283 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
284 m_filledPolysHash[layer] = {};
285 m_insulatedIslands[layer] = {};
286 }
287 }
288
289 m_layerSet = aLayerSet;
290}
291
292
293void ZONE::ViewGetLayers( int aLayers[], int& aCount ) const
294{
295 aCount = 0;
296 LSEQ layers = m_layerSet.Seq();
297
298 for( PCB_LAYER_ID layer : m_layerSet.Seq() )
299 {
300 aLayers[ aCount++ ] = layer; // For outline (always full opacity)
301 aLayers[ aCount++ ] = layer + LAYER_ZONE_START; // For fill (obeys global zone opacity)
302 }
303
304 if( IsConflicting() )
305 aLayers[ aCount++ ] = LAYER_CONFLICTS_SHADOW;
306}
307
308
309double ZONE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
310{
311 constexpr double HIDE = std::numeric_limits<double>::max();
312
313 if( !aView )
314 return 0;
315
316 if( !aView->IsLayerVisible( LAYER_ZONES ) )
317 return HIDE;
318
319 if( FOOTPRINT* parentFP = GetParentFootprint() )
320 {
321 bool flipped = parentFP->GetLayer() == B_Cu;
322
323 // Handle Render tab switches
324 if( !flipped && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
325 return HIDE;
326
327 if( flipped && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
328 return HIDE;
329 }
330
331 // Other layers are shown without any conditions
332 return 0.0;
333}
334
335
336bool ZONE::IsOnLayer( PCB_LAYER_ID aLayer ) const
337{
338 return m_layerSet.test( aLayer );
339}
340
341
343{
344 if( const BOARD* board = GetBoard() )
345 {
346 std::unordered_map<const ZONE*, BOX2I>& cache = board->m_ZoneBBoxCache;
347 auto cacheIter = cache.find( this );
348
349 if( cacheIter != cache.end() )
350 return cacheIter->second;
351
352 BOX2I bbox = m_Poly->BBox();
353
354 std::unique_lock<std::mutex> cacheLock( const_cast<BOARD*>( board )->m_CachesMutex );
355 cache[ this ] = bbox;
356
357 return bbox;
358 }
359
360 return m_Poly->BBox();
361}
362
363
365{
366 BOARD* board = GetBoard();
367 std::unordered_map<const ZONE*, BOX2I>& cache = board->m_ZoneBBoxCache;
368
369 auto cacheIter = cache.find( this );
370
371 if( cacheIter == cache.end() )
372 {
373 std::unique_lock<std::mutex> cacheLock( board->m_CachesMutex );
374 cache[ this ] = m_Poly->BBox();
375 }
376}
377
378
379int ZONE::GetThermalReliefGap( PAD* aPad, wxString* aSource ) const
380{
381 if( aPad->GetLocalThermalGapOverride() == 0 )
382 {
383 if( aSource )
384 *aSource = _( "zone" );
385
386 return m_thermalReliefGap;
387 }
388
389 return aPad->GetLocalThermalGapOverride( aSource );
390
391}
392
393
394void ZONE::SetCornerRadius( unsigned int aRadius )
395{
396 if( m_cornerRadius != aRadius )
397 SetNeedRefill( true );
398
399 m_cornerRadius = aRadius;
400}
401
402
404
405
407{
408 if( !m_filledPolysHash.count( aLayer ) )
409 return g_nullPoly.GetHash();
410 else
411 return m_filledPolysHash.at( aLayer );
412}
413
414
416{
417 if( !m_FilledPolysList.count( aLayer ) )
419 else
420 m_filledPolysHash[aLayer] = m_FilledPolysList.at( aLayer )->GetHash();
421}
422
423
424bool ZONE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
425{
426 // When looking for an "exact" hit aAccuracy will be 0 which works poorly for very thin
427 // lines. Give it a floor.
428 int accuracy = std::max( aAccuracy, pcbIUScale.mmToIU( 0.1 ) );
429
430 return HitTestForCorner( aPosition, accuracy * 2 ) || HitTestForEdge( aPosition, accuracy );
431}
432
433
434bool ZONE::HitTestForCorner( const VECTOR2I& refPos, int aAccuracy,
435 SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
436{
437 return m_Poly->CollideVertex( VECTOR2I( refPos ), aCornerHit, aAccuracy );
438}
439
440
441bool ZONE::HitTestForEdge( const VECTOR2I& refPos, int aAccuracy,
442 SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
443{
444 return m_Poly->CollideEdge( VECTOR2I( refPos ), aCornerHit, aAccuracy );
445}
446
447
448bool ZONE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
449{
450 // Calculate bounding box for zone
451 BOX2I bbox = GetBoundingBox();
452 bbox.Normalize();
453
454 BOX2I arect = aRect;
455 arect.Normalize();
456 arect.Inflate( aAccuracy );
457
458 if( aContained )
459 {
460 return arect.Contains( bbox );
461 }
462 else
463 {
464 // Fast test: if aBox is outside the polygon bounding box, rectangles cannot intersect
465 if( !arect.Intersects( bbox ) )
466 return false;
467
468 int count = m_Poly->TotalVertices();
469
470 for( int ii = 0; ii < count; ii++ )
471 {
472 VECTOR2I vertex = m_Poly->CVertex( ii );
473 VECTOR2I vertexNext = m_Poly->CVertex( ( ii + 1 ) % count );
474
475 // Test if the point is within the rect
476 if( arect.Contains( vertex ) )
477 return true;
478
479 // Test if this edge intersects the rect
480 if( arect.Intersects( vertex, vertexNext ) )
481 return true;
482 }
483
484 return false;
485 }
486}
487
488
489int ZONE::GetLocalClearance( wxString* aSource ) const
490{
491 if( m_isRuleArea )
492 return 0;
493
494 if( aSource )
495 *aSource = _( "zone" );
496
497 return m_ZoneClearance;
498}
499
500
501bool ZONE::HitTestFilledArea( PCB_LAYER_ID aLayer, const VECTOR2I& aRefPos, int aAccuracy ) const
502{
503 // Rule areas have no filled area, but it's generally nice to treat their interior as if it were
504 // filled so that people don't have to select them by their outline (which is min-width)
505 if( GetIsRuleArea() )
506 return m_Poly->Contains( aRefPos, -1, aAccuracy );
507
508 if( !m_FilledPolysList.count( aLayer ) )
509 return false;
510
511 return m_FilledPolysList.at( aLayer )->Contains( aRefPos, -1, aAccuracy );
512}
513
514
515bool ZONE::HitTestCutout( const VECTOR2I& aRefPos, int* aOutlineIdx, int* aHoleIdx ) const
516{
517 // Iterate over each outline polygon in the zone and then iterate over
518 // each hole it has to see if the point is in it.
519 for( int i = 0; i < m_Poly->OutlineCount(); i++ )
520 {
521 for( int j = 0; j < m_Poly->HoleCount( i ); j++ )
522 {
523 if( m_Poly->Hole( i, j ).PointInside( aRefPos ) )
524 {
525 if( aOutlineIdx )
526 *aOutlineIdx = i;
527
528 if( aHoleIdx )
529 *aHoleIdx = j;
530
531 return true;
532 }
533 }
534 }
535
536 return false;
537}
538
539
540void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
541{
542 wxString msg = GetFriendlyName();
543
544 // Display Cutout instead of Outline for holes inside a zone (i.e. when num contour !=0).
545 // Check whether the selected corner is in a hole; i.e., in any contour but the first one.
546 if( m_CornerSelection != nullptr && m_CornerSelection->m_contour > 0 )
547 msg << wxT( " " ) << _( "Cutout" );
548
549 aList.emplace_back( _( "Type" ), msg );
550
551 if( GetIsRuleArea() )
552 {
553 msg.Empty();
554
555 if( GetDoNotAllowVias() )
556 AccumulateDescription( msg, _( "No vias" ) );
557
558 if( GetDoNotAllowTracks() )
559 AccumulateDescription( msg, _( "No tracks" ) );
560
561 if( GetDoNotAllowPads() )
562 AccumulateDescription( msg, _( "No pads" ) );
563
565 AccumulateDescription( msg, _( "No copper zones" ) );
566
568 AccumulateDescription( msg, _( "No footprints" ) );
569
570 if( !msg.IsEmpty() )
571 aList.emplace_back( _( "Restrictions" ), msg );
572 }
573 else if( IsOnCopperLayer() )
574 {
575 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
576 {
577 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
578
579 aList.emplace_back( _( "Resolved Netclass" ),
580 UnescapeString( GetEffectiveNetClass()->GetName() ) );
581 }
582
583 // Display priority level
584 aList.emplace_back( _( "Priority" ),
585 wxString::Format( wxT( "%d" ), GetAssignedPriority() ) );
586 }
587
588 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
589 {
590 if( IsLocked() )
591 aList.emplace_back( _( "Status" ), _( "Locked" ) );
592 }
593
594 LSEQ layers = m_layerSet.Seq();
595 wxString layerDesc;
596
597 if( layers.size() == 1 )
598 {
599 layerDesc.Printf( _( "%s" ), GetBoard()->GetLayerName( layers[0] ) );
600 }
601 else if (layers.size() == 2 )
602 {
603 layerDesc.Printf( _( "%s and %s" ),
604 GetBoard()->GetLayerName( layers[0] ),
605 GetBoard()->GetLayerName( layers[1] ) );
606 }
607 else if (layers.size() == 3 )
608 {
609 layerDesc.Printf( _( "%s, %s and %s" ),
610 GetBoard()->GetLayerName( layers[0] ),
611 GetBoard()->GetLayerName( layers[1] ),
612 GetBoard()->GetLayerName( layers[2] ) );
613 }
614 else if( layers.size() > 3 )
615 {
616 layerDesc.Printf( _( "%s, %s and %d more" ),
617 GetBoard()->GetLayerName( layers[0] ),
618 GetBoard()->GetLayerName( layers[1] ),
619 static_cast<int>( layers.size() - 2 ) );
620 }
621
622 aList.emplace_back( _( "Layer" ), layerDesc );
623
624 if( !m_zoneName.empty() )
625 aList.emplace_back( _( "Name" ), m_zoneName );
626
627 switch( m_fillMode )
628 {
629 case ZONE_FILL_MODE::POLYGONS: msg = _( "Solid" ); break;
630 case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break;
631 default: msg = _( "Unknown" ); break;
632 }
633
634 aList.emplace_back( _( "Fill Mode" ), msg );
635
636 aList.emplace_back( _( "Filled Area" ),
637 aFrame->MessageTextFromValue( m_area, true, EDA_DATA_TYPE::AREA ) );
638
639 wxString source;
640 int clearance = GetOwnClearance( UNDEFINED_LAYER, &source );
641
642 if( !source.IsEmpty() )
643 {
644 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
645 aFrame->MessageTextFromValue( clearance ) ),
646 wxString::Format( _( "(from %s)" ),
647 source ) );
648 }
649
650 if( !m_FilledPolysList.empty() )
651 {
652 int count = 0;
653
654 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& ii: m_FilledPolysList )
655 count += ii.second->TotalVertices();
656
657 aList.emplace_back( _( "Corner Count" ), wxString::Format( wxT( "%d" ), count ) );
658 }
659}
660
661
662void ZONE::Move( const VECTOR2I& offset )
663{
664 /* move outlines */
665 m_Poly->Move( offset );
666
667 HatchBorder();
668
669 /* move fills */
670 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
671 pair.second->Move( offset );
672
673 /*
674 * move boundingbox cache
675 *
676 * While the cache will get nuked at the conclusion of the operation, we use it for some
677 * things (such as drawing the parent group) during the move.
678 */
679 if( GetBoard() )
680 {
681 auto it = GetBoard()->m_ZoneBBoxCache.find( this );
682
683 if( it != GetBoard()->m_ZoneBBoxCache.end() )
684 it->second.Move( offset );
685 }
686}
687
688
689wxString ZONE::GetFriendlyName() const
690{
691 if( GetIsRuleArea() )
692 return _( "Rule Area" );
693 else if( IsTeardropArea() )
694 return _( "Teardrop Area" );
695 else if( IsOnCopperLayer() )
696 return _( "Copper Zone" );
697 else
698 return _( "Non-copper Zone" );
699}
700
701
702void ZONE::MoveEdge( const VECTOR2I& offset, int aEdge )
703{
704 int next_corner;
705
706 if( m_Poly->GetNeighbourIndexes( aEdge, nullptr, &next_corner ) )
707 {
708 m_Poly->SetVertex( aEdge, m_Poly->CVertex( aEdge ) + VECTOR2I( offset ) );
709 m_Poly->SetVertex( next_corner, m_Poly->CVertex( next_corner ) + VECTOR2I( offset ) );
710 HatchBorder();
711
712 SetNeedRefill( true );
713 }
714}
715
716
717void ZONE::Rotate( const VECTOR2I& aCentre, const EDA_ANGLE& aAngle )
718{
719 m_Poly->Rotate( aAngle, aCentre );
720 HatchBorder();
721
722 /* rotate filled areas: */
723 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
724 pair.second->Rotate( aAngle, aCentre );
725}
726
727
728void ZONE::Flip( const VECTOR2I& aCentre, bool aFlipLeftRight )
729{
730 Mirror( aCentre, aFlipLeftRight );
731
732 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> fillsCopy;
733
734 for( auto& [oldLayer, shapePtr] : m_FilledPolysList )
735 {
736 fillsCopy[oldLayer] = *shapePtr;
737 }
738
739 SetLayerSet( FlipLayerMask( GetLayerSet(), GetBoard()->GetCopperLayerCount() ) );
740
741 for( auto& [oldLayer, shape] : fillsCopy )
742 {
743 PCB_LAYER_ID newLayer = FlipLayer( oldLayer, GetBoard()->GetCopperLayerCount() );
744 SetFilledPolysList( newLayer, shape );
745 }
746}
747
748
749void ZONE::Mirror( const VECTOR2I& aMirrorRef, bool aMirrorLeftRight )
750{
751 m_Poly->Mirror( aMirrorLeftRight, !aMirrorLeftRight, aMirrorRef );
752
753 HatchBorder();
754
755 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
756 pair.second->Mirror( aMirrorLeftRight, !aMirrorLeftRight, aMirrorRef );
757}
758
759
760void ZONE::RemoveCutout( int aOutlineIdx, int aHoleIdx )
761{
762 // Ensure the requested cutout is valid
763 if( m_Poly->OutlineCount() < aOutlineIdx || m_Poly->HoleCount( aOutlineIdx ) < aHoleIdx )
764 return;
765
766 SHAPE_POLY_SET cutPoly( m_Poly->Hole( aOutlineIdx, aHoleIdx ) );
767
768 // Add the cutout back to the zone
770
771 SetNeedRefill( true );
772}
773
774
775void ZONE::AddPolygon( const SHAPE_LINE_CHAIN& aPolygon )
776{
777 wxASSERT( aPolygon.IsClosed() );
778
779 // Add the outline as a new polygon in the polygon set
780 if( m_Poly->OutlineCount() == 0 )
781 m_Poly->AddOutline( aPolygon );
782 else
783 m_Poly->AddHole( aPolygon );
784
785 SetNeedRefill( true );
786}
787
788
789void ZONE::AddPolygon( std::vector<VECTOR2I>& aPolygon )
790{
791 if( aPolygon.empty() )
792 return;
793
794 SHAPE_LINE_CHAIN outline;
795
796 // Create an outline and populate it with the points of aPolygon
797 for( const VECTOR2I& pt : aPolygon )
798 outline.Append( pt );
799
800 outline.SetClosed( true );
801
802 AddPolygon( outline );
803}
804
805
806bool ZONE::AppendCorner( VECTOR2I aPosition, int aHoleIdx, bool aAllowDuplication )
807{
808 // Ensure the main outline exists:
809 if( m_Poly->OutlineCount() == 0 )
811
812 // If aHoleIdx >= 0, the corner musty be added to the hole, index aHoleIdx.
813 // (remember: the index of the first hole is 0)
814 // Return error if it does not exist.
815 if( aHoleIdx >= m_Poly->HoleCount( 0 ) )
816 return false;
817
818 m_Poly->Append( aPosition.x, aPosition.y, -1, aHoleIdx, aAllowDuplication );
819
820 SetNeedRefill( true );
821
822 return true;
823}
824
825
826wxString ZONE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
827{
828 LSEQ layers = m_layerSet.Seq();
829 wxString layerDesc;
830
831 if( layers.size() == 1 )
832 {
833 layerDesc.Printf( _( "on %s" ), GetBoard()->GetLayerName( layers[0] ) );
834 }
835 else if (layers.size() == 2 )
836 {
837 layerDesc.Printf( _( "on %s and %s" ),
838 GetBoard()->GetLayerName( layers[0] ),
839 GetBoard()->GetLayerName( layers[1] ) );
840 }
841 else if (layers.size() == 3 )
842 {
843 layerDesc.Printf( _( "on %s, %s and %s" ),
844 GetBoard()->GetLayerName( layers[0] ),
845 GetBoard()->GetLayerName( layers[1] ),
846 GetBoard()->GetLayerName( layers[2] ) );
847 }
848 else if( layers.size() > 3 )
849 {
850 layerDesc.Printf( _( "on %s, %s and %zu more" ),
851 GetBoard()->GetLayerName( layers[0] ),
852 GetBoard()->GetLayerName( layers[1] ),
853 layers.size() - 2 );
854 }
855
856 // Check whether the selected contour is a hole (contour index > 0)
857 if( m_CornerSelection != nullptr && m_CornerSelection->m_contour > 0 )
858 {
859 if( GetIsRuleArea() )
860 return wxString::Format( _( "Rule Area Cutout %s" ), layerDesc );
861 else
862 return wxString::Format( _( "Zone Cutout %s" ), layerDesc );
863 }
864 else
865 {
866 if( GetIsRuleArea() )
867 return wxString::Format( _( "Rule Area %s" ), layerDesc );
868 else
869 return wxString::Format( _( "Zone %s %s" ), GetNetnameMsg(), layerDesc );
870 }
871}
872
873
875{
876 return m_borderHatchPitch;
877}
878
879
881 int aBorderHatchPitch, bool aRebuildBorderHatch )
882{
883 aBorderHatchPitch = std::max( aBorderHatchPitch,
885 aBorderHatchPitch = std::min( aBorderHatchPitch,
887 SetBorderHatchPitch( aBorderHatchPitch );
888 m_borderStyle = aBorderHatchStyle;
889
890 if( aRebuildBorderHatch )
891 HatchBorder();
892}
893
894
896{
897 m_borderHatchPitch = aPitch;
898}
899
900
902{
903 m_borderHatchLines.clear();
904}
905
906
907// Creates hatch lines inside the outline of the complex polygon
908// sort function used in ::HatchBorder to sort points by descending VECTOR2I.x values
909bool sortEndsByDescendingX( const VECTOR2I& ref, const VECTOR2I& tst )
910{
911 return tst.x < ref.x;
912}
913
914
916{
918
919 if( m_borderStyle == ZONE_BORDER_DISPLAY_STYLE::NO_HATCH
920 || m_borderHatchPitch == 0
921 || m_Poly->IsEmpty() )
922 {
923 return;
924 }
925
926 // define range for hatch lines
927 int min_x = m_Poly->CVertex( 0 ).x;
928 int max_x = m_Poly->CVertex( 0 ).x;
929 int min_y = m_Poly->CVertex( 0 ).y;
930 int max_y = m_Poly->CVertex( 0 ).y;
931
932 for( auto iterator = m_Poly->IterateWithHoles(); iterator; iterator++ )
933 {
934 if( iterator->x < min_x )
935 min_x = iterator->x;
936
937 if( iterator->x > max_x )
938 max_x = iterator->x;
939
940 if( iterator->y < min_y )
941 min_y = iterator->y;
942
943 if( iterator->y > max_y )
944 max_y = iterator->y;
945 }
946
947 // Calculate spacing between 2 hatch lines
948 int spacing;
949
950 if( m_borderStyle == ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_EDGE )
951 spacing = m_borderHatchPitch;
952 else
953 spacing = m_borderHatchPitch * 2;
954
955 // set the "length" of hatch lines (the length on horizontal axis)
956 int hatch_line_len = m_borderHatchPitch;
957
958 // To have a better look, give a slope depending on the layer
959 int layer = GetFirstLayer();
960 std::vector<int> slope_flags;
961
962 if( IsTeardropArea() )
963 slope_flags = { 1, -1 };
964 else if( layer & 1 )
965 slope_flags = { 1 };
966 else
967 slope_flags = { -1 };
968
969 for( int slope_flag : slope_flags )
970 {
971 double slope = 0.707106 * slope_flag; // 45 degrees slope
972 int64_t max_a, min_a;
973
974 if( slope_flag == 1 )
975 {
976 max_a = KiROUND( max_y - slope * min_x );
977 min_a = KiROUND( min_y - slope * max_x );
978 }
979 else
980 {
981 max_a = KiROUND( max_y - slope * max_x );
982 min_a = KiROUND( min_y - slope * min_x );
983 }
984
985 min_a = (min_a / spacing) * spacing;
986
987 // calculate an offset depending on layer number,
988 // for a better look of hatches on a multilayer board
989 int offset = (layer * 7) / 8;
990 min_a += offset;
991
992 // loop through hatch lines
993 std::vector<VECTOR2I> pointbuffer;
994 pointbuffer.reserve( 256 );
995
996 for( int64_t a = min_a; a < max_a; a += spacing )
997 {
998 pointbuffer.clear();
999
1000 // Iterate through all vertices
1001 for( auto iterator = m_Poly->IterateSegmentsWithHoles(); iterator; iterator++ )
1002 {
1003 const SEG seg = *iterator;
1004 double x, y;
1005
1006 if( FindLineSegmentIntersection( a, slope, seg.A.x, seg.A.y, seg.B.x, seg.B.y, x, y ) )
1007 pointbuffer.emplace_back( KiROUND( x ), KiROUND( y ) );
1008 }
1009
1010 // sort points in order of descending x (if more than 2) to
1011 // ensure the starting point and the ending point of the same segment
1012 // are stored one just after the other.
1013 if( pointbuffer.size() > 2 )
1014 sort( pointbuffer.begin(), pointbuffer.end(), sortEndsByDescendingX );
1015
1016 // creates lines or short segments inside the complex polygon
1017 for( size_t ip = 0; ip + 1 < pointbuffer.size(); ip += 2 )
1018 {
1019 int dx = pointbuffer[ip + 1].x - pointbuffer[ip].x;
1020
1021 // Push only one line for diagonal hatch,
1022 // or for small lines < twice the line length
1023 // else push 2 small lines
1024 if( m_borderStyle == ZONE_BORDER_DISPLAY_STYLE::DIAGONAL_FULL
1025 || std::abs( dx ) < 2 * hatch_line_len )
1026 {
1027 m_borderHatchLines.emplace_back( SEG( pointbuffer[ip], pointbuffer[ ip + 1] ) );
1028 }
1029 else
1030 {
1031 double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y;
1032 slope = dy / dx;
1033
1034 if( dx > 0 )
1035 dx = hatch_line_len;
1036 else
1037 dx = -hatch_line_len;
1038
1039 int x1 = KiROUND( pointbuffer[ip].x + dx );
1040 int x2 = KiROUND( pointbuffer[ip + 1].x - dx );
1041 int y1 = KiROUND( pointbuffer[ip].y + dx * slope );
1042 int y2 = KiROUND( pointbuffer[ip + 1].y - dx * slope );
1043
1044 m_borderHatchLines.emplace_back( SEG( pointbuffer[ip].x, pointbuffer[ip].y,
1045 x1, y1 ) );
1046
1047 m_borderHatchLines.emplace_back( SEG( pointbuffer[ip+1].x, pointbuffer[ip+1].y,
1048 x2, y2 ) );
1049 }
1050 }
1051 }
1052 }
1053}
1054
1055
1057{
1059}
1060
1061
1063{
1064 return BITMAPS::add_zone;
1065}
1066
1067
1069{
1070 assert( aImage->Type() == PCB_ZONE_T );
1071
1072 std::swap( *static_cast<ZONE*>( this ), *static_cast<ZONE*>( aImage) );
1073}
1074
1075
1077{
1078 if( aLayer == UNDEFINED_LAYER )
1079 {
1080 for( auto& [ layer, poly ] : m_FilledPolysList )
1081 poly->CacheTriangulation();
1082
1083 m_Poly->CacheTriangulation( false );
1084 }
1085 else
1086 {
1087 if( m_FilledPolysList.count( aLayer ) )
1088 m_FilledPolysList[ aLayer ]->CacheTriangulation();
1089 }
1090}
1091
1092
1093bool ZONE::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const
1094{
1095 if( GetNetCode() < 1 )
1096 return true;
1097
1098 if( !m_insulatedIslands.count( aLayer ) )
1099 return false;
1100
1101 return m_insulatedIslands.at( aLayer ).count( aPolyIdx );
1102}
1103
1104
1105void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aSameNetCollidingZones,
1106 std::vector<ZONE*>* aOtherNetIntersectingZones ) const
1107{
1108 int epsilon = pcbIUScale.mmToIU( 0.001 );
1109 BOX2I bbox = GetBoundingBox();
1110
1111 bbox.Inflate( epsilon );
1112
1113 for( ZONE* candidate : GetBoard()->Zones() )
1114 {
1115 if( candidate == this )
1116 continue;
1117
1118 if( !candidate->GetLayerSet().test( aLayer ) )
1119 continue;
1120
1121 if( candidate->GetIsRuleArea() || candidate->IsTeardropArea() )
1122 continue;
1123
1124 if( !candidate->GetBoundingBox().Intersects( bbox ) )
1125 continue;
1126
1127 if( candidate->GetNetCode() == GetNetCode() )
1128 {
1129 if( m_Poly->Collide( candidate->m_Poly ) )
1130 aSameNetCollidingZones->push_back( candidate );
1131 }
1132 else
1133 {
1134 aOtherNetIntersectingZones->push_back( candidate );
1135 }
1136 }
1137}
1138
1139
1141 SHAPE_POLY_SET* aBoardOutline,
1142 SHAPE_POLY_SET* aSmoothedPolyWithApron ) const
1143{
1144 if( GetNumCorners() <= 2 ) // malformed zone. polygon calculations will not like it ...
1145 return false;
1146
1147 // Processing of arc shapes in zones is not yet supported because Clipper can't do boolean
1148 // operations on them. The poly outline must be converted to segments first.
1150 flattened.ClearArcs();
1151
1152 if( GetIsRuleArea() )
1153 {
1154 // We like keepouts just the way they are....
1155 aSmoothedPoly = flattened;
1156 return true;
1157 }
1158
1159 const BOARD* board = GetBoard();
1160 int maxError = ARC_HIGH_DEF;
1161 bool keepExternalFillets = false;
1164
1165 if( IsTeardropArea() )
1166 {
1167 // We use teardrop shapes with no smoothing; these shapes are already optimized
1168 smooth_requested = false;
1169 }
1170
1171 if( board )
1172 {
1174
1175 maxError = bds.m_MaxError;
1176 keepExternalFillets = bds.m_ZoneKeepExternalFillets;
1177 }
1178
1179 auto smooth = [&]( SHAPE_POLY_SET& aPoly )
1180 {
1181 if( !smooth_requested )
1182 return;
1183
1184 switch( m_cornerSmoothingType )
1185 {
1187 aPoly = aPoly.Chamfer( (int) m_cornerRadius );
1188 break;
1189
1191 {
1192 aPoly = aPoly.Fillet( (int) m_cornerRadius, maxError );
1193 break;
1194 }
1195
1196 default:
1197 break;
1198 }
1199 };
1200
1201 SHAPE_POLY_SET* maxExtents = &flattened;
1202 SHAPE_POLY_SET withFillets;
1203
1204 aSmoothedPoly = flattened;
1205
1206 // Should external fillets (that is, those applied to concave corners) be kept? While it
1207 // seems safer to never have copper extend outside the zone outline, 5.1.x and prior did
1208 // indeed fill them so we leave the mode available.
1209 if( keepExternalFillets && smooth_requested )
1210 {
1211 withFillets = flattened;
1212 smooth( withFillets );
1213 withFillets.BooleanAdd( flattened, SHAPE_POLY_SET::PM_FAST );
1214 maxExtents = &withFillets;
1215 }
1216
1217 // We now add in the areas of any same-net, intersecting zones. This keeps us from smoothing
1218 // corners at an intersection (which often produces undesired divots between the intersecting
1219 // zones -- see #2752).
1220 //
1221 // After smoothing, we'll subtract back out everything outside of our zone.
1222 std::vector<ZONE*> sameNetCollidingZones;
1223 std::vector<ZONE*> diffNetIntersectingZones;
1224 GetInteractingZones( aLayer, &sameNetCollidingZones, &diffNetIntersectingZones );
1225
1226 for( ZONE* sameNetZone : sameNetCollidingZones )
1227 {
1228 BOX2I sameNetBoundingBox = sameNetZone->GetBoundingBox();
1229
1230 // Note: a two-pass algorithm could use sameNetZone's actual fill instead of its outline.
1231 // This would obviate the need for the below wrinkles, in addition to fixing both issues
1232 // in #16095.
1233 // (And we wouldn't need to collect all the diffNetIntersectingZones either.)
1234
1235 SHAPE_POLY_SET sameNetPoly = sameNetZone->Outline()->CloneDropTriangulation();
1236 SHAPE_POLY_SET diffNetPoly;
1237
1238 // Of course there's always a wrinkle. The same-net intersecting zone *might* get knocked
1239 // out along the border by a higher-priority, different-net zone. #12797
1240 for( ZONE* diffNetZone : diffNetIntersectingZones )
1241 {
1242 if( diffNetZone->HigherPriority( sameNetZone )
1243 && diffNetZone->GetBoundingBox().Intersects( sameNetBoundingBox ) )
1244 {
1245 diffNetPoly.BooleanAdd( *diffNetZone->Outline(), SHAPE_POLY_SET::PM_FAST );
1246 }
1247 }
1248
1249 // Second wrinkle. After unioning the higher priority, different net zones together, we
1250 // need to check to see if they completely enclose our zone. If they do, then we need to
1251 // treat the enclosed zone as isolated, not connected to the outer zone. #13915
1252 bool isolated = false;
1253
1254 if( diffNetPoly.OutlineCount() )
1255 {
1257
1258 thisPoly.BooleanSubtract( diffNetPoly, SHAPE_POLY_SET::PM_FAST );
1259 isolated = thisPoly.OutlineCount() == 0;
1260 }
1261
1262 if( !isolated )
1263 {
1264 sameNetPoly.ClearArcs();
1265 aSmoothedPoly.BooleanAdd( sameNetPoly, SHAPE_POLY_SET::PM_FAST );
1266 }
1267 }
1268
1269 if( aBoardOutline )
1270 aSmoothedPoly.BooleanIntersection( *aBoardOutline, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1271
1272 smooth( aSmoothedPoly );
1273
1274 if( aSmoothedPolyWithApron )
1275 {
1276 SHAPE_POLY_SET poly = maxExtents->CloneDropTriangulation();
1277 poly.Inflate( m_ZoneMinThickness, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
1278 *aSmoothedPolyWithApron = aSmoothedPoly;
1279 aSmoothedPolyWithApron->BooleanIntersection( poly, SHAPE_POLY_SET::PM_FAST );
1280 }
1281
1282 aSmoothedPoly.BooleanIntersection( *maxExtents, SHAPE_POLY_SET::PM_FAST );
1283
1284 return true;
1285}
1286
1287
1289{
1290 m_area = 0.0;
1291
1292 // Iterate over each outline polygon in the zone and then iterate over
1293 // each hole it has to compute the total area.
1294 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1295 {
1296 std::shared_ptr<SHAPE_POLY_SET>& poly = pair.second;
1297
1298 for( int i = 0; i < poly->OutlineCount(); i++ )
1299 {
1300 m_area += poly->Outline( i ).Area();
1301
1302 for( int j = 0; j < poly->HoleCount( i ); j++ )
1303 m_area -= poly->Hole( i, j ).Area();
1304 }
1305 }
1306
1307 return m_area;
1308}
1309
1310
1312{
1314 return m_outlinearea;
1315}
1316
1317
1319 int aMaxError, ERROR_LOC aErrorLoc,
1320 SHAPE_POLY_SET* aBoardOutline ) const
1321{
1322 // Creates the zone outline polygon (with holes if any)
1323 SHAPE_POLY_SET polybuffer;
1324
1325 // TODO: using GetFirstLayer() means it only works for single-layer zones....
1326 BuildSmoothedPoly( polybuffer, GetFirstLayer(), aBoardOutline );
1327
1328 // Calculate the polygon with clearance
1329 // holes are linked to the main outline, so only one polygon is created.
1330 if( aClearance )
1331 {
1332 const BOARD* board = GetBoard();
1333 int maxError = ARC_HIGH_DEF;
1334
1335 if( board )
1336 maxError = board->GetDesignSettings().m_MaxError;
1337
1338 if( aErrorLoc == ERROR_OUTSIDE )
1339 aClearance += maxError;
1340
1341 polybuffer.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, maxError );
1342 }
1343
1344 polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );
1345 aBuffer.Append( polybuffer );
1346}
1347
1348
1349std::shared_ptr<SHAPE> ZONE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING aFlash ) const
1350{
1351 if( m_FilledPolysList.find( aLayer ) == m_FilledPolysList.end() )
1352 return std::make_shared<SHAPE_NULL>();
1353 else
1354 return m_FilledPolysList.at( aLayer );
1355}
1356
1357
1358void ZONE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
1359 int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth ) const
1360{
1361 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for zones." ) );
1362
1363 if( !m_FilledPolysList.count( aLayer ) )
1364 return;
1365
1366 if( !aClearance )
1367 {
1368 aBuffer.Append( *m_FilledPolysList.at( aLayer ) );
1369 return;
1370 }
1371
1372 SHAPE_POLY_SET temp_buf = m_FilledPolysList.at( aLayer )->CloneDropTriangulation();
1373
1374 // Rebuild filled areas only if clearance is not 0
1375 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
1376 {
1377 if( aErrorLoc == ERROR_OUTSIDE )
1378 aClearance += aError;
1379
1380 temp_buf.InflateWithLinkedHoles( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aError,
1382 }
1383
1384 aBuffer.Append( temp_buf );
1385}
1386
1387
1389{
1390 if( m_FilledPolysList.count( aLayer ) && !m_FilledPolysList.at( aLayer )->IsEmpty() )
1391 aBuffer.Append( *m_FilledPolysList.at( aLayer ) );
1392}
1393
1394
1395bool ZONE::operator==( const BOARD_ITEM& aOther ) const
1396{
1397 if( aOther.Type() != Type() )
1398 return false;
1399
1400 const ZONE& other = static_cast<const ZONE&>( aOther );
1401
1402 if( GetIsRuleArea() != other.GetIsRuleArea() )
1403 return false;
1404
1405 if( GetLayerSet() != other.GetLayerSet() )
1406 return false;
1407
1408 if( GetNetCode() != other.GetNetCode() )
1409 return false;
1410
1411 if( GetIsRuleArea() )
1412 {
1414 return false;
1415 if( GetDoNotAllowTracks() != other.GetDoNotAllowTracks() )
1416 return false;
1417 if( GetDoNotAllowVias() != other.GetDoNotAllowVias() )
1418 return false;
1420 return false;
1421 if( GetDoNotAllowPads() != other.GetDoNotAllowPads() )
1422 return false;
1423 }
1424 else
1425 {
1426 if( GetAssignedPriority() != other.GetAssignedPriority() )
1427 return false;
1428
1429 if( GetMinThickness() != other.GetMinThickness() )
1430 return false;
1431
1433 return false;
1434
1435 if( GetCornerRadius() != other.GetCornerRadius() )
1436 return false;
1437
1438 if( GetTeardropParams() != other.GetTeardropParams() )
1439 return false;
1440 }
1441
1442 if( GetNumCorners() != other.GetNumCorners() )
1443 return false;
1444
1445 for( int ii = 0; ii < GetNumCorners(); ii++ )
1446 {
1447 if( GetCornerPosition( ii ) != other.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, 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:121
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:109
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:276
std::unordered_map< const ZONE *, BOX2I > m_ZoneBBoxCache
Definition: board.h:1239
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.cpp:768
std::mutex m_CachesMutex
Definition: board.h:1230
BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition: box2.h:120
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:270
bool Contains(const Vec &aPoint) const
Definition: box2.h:142
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:507
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:85
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:482
bool m_forceVisible
Definition: eda_item.h:486
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:487
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition: eda_item.h:127
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:659
static ENUM_MAP< T > & Instance()
Definition: property.h:653
ENUM_MAP & Undefined(T aValue)
Definition: property.h:666
wxPGChoices & Choices()
Definition: property.h:702
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:519
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:573
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:59
int GetLocalThermalGapOverride(wxString *aSource=nullptr) const
Definition: pad.cpp:963
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:252
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition: property.h:263
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition: property.h:318
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.
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.
void CacheTriangulation(bool aPartition=true, bool aSimplify=false)
Build a polygon triangulation, needed to draw a polygon on OpenGL and in some other calculations.
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:274
SHAPE_POLY_SET::VERTEX_INDEX * m_CornerSelection
The index of the corner being moved or nullptr if no corner is selected.
Definition: zone.h:877
void SetNeedRefill(bool aNeedRefill)
Definition: zone.h:253
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:424
int m_borderHatchPitch
Definition: zone.h:898
bool m_isRuleArea
Definition: zone.h:813
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
Definition: zone.cpp:826
ZONE & operator=(const ZONE &aOther)
Definition: zone.cpp:79
int m_cornerSmoothingType
Definition: zone.h:796
void Mirror(const VECTOR2I &aMirrorRef, bool aMirrorLeftRight)
Mirror the outlines relative to a given horizontal axis the layer is not changed.
Definition: zone.cpp:749
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:699
bool m_doNotAllowVias
Definition: zone.h:825
bool UnFill()
Removes the zone filling.
Definition: zone.cpp:206
bool GetDoNotAllowVias() const
Definition: zone.h:701
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:1388
void SetCornerRadius(unsigned int aRadius)
Definition: zone.cpp:394
ZONE_FILL_MODE m_fillMode
How to fill areas:
Definition: zone.h:863
bool m_doNotAllowFootprints
Definition: zone.h:828
int m_ZoneMinThickness
Definition: zone.h:832
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:293
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition: zone.cpp:789
double m_hatchSmoothingValue
Definition: zone.h:871
void SetLocalFlags(int aFlags)
Definition: zone.h:323
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:1318
int m_thermalReliefSpokeWidth
Definition: zone.h:854
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:515
EDA_ANGLE m_hatchOrientation
Definition: zone.h:866
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:1076
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:902
wxString m_zoneName
An optional unique name for this zone, used for identifying it in DRC checking.
Definition: zone.h:800
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition: zone.cpp:915
std::map< PCB_LAYER_ID, std::shared_ptr< SHAPE_POLY_SET > > m_FilledPolysList
Definition: zone.h:889
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuilBorderdHatch)
Set all hatch parameters for the zone.
Definition: zone.cpp:880
MD5_HASH GetHashValue(PCB_LAYER_ID aLayer)
Definition: zone.cpp:406
bool GetDoNotAllowPads() const
Definition: zone.h:703
const BOX2I GetBoundingBox() const override
Definition: zone.cpp:342
void SetMinThickness(int aMinThickness)
Definition: zone.h:259
double m_outlinearea
Definition: zone.h:905
wxString GetFriendlyName() const override
Definition: zone.cpp:689
bool GetDoNotAllowTracks() const
Definition: zone.h:702
int GetLocalFlags() const
Definition: zone.h:322
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: zone.cpp:177
void SetHatchOrientation(const EDA_ANGLE &aStep)
Definition: zone.h:280
bool m_doNotAllowCopperPour
Definition: zone.h:824
void SetHatchSmoothingValue(double aValue)
Definition: zone.h:286
bool m_needRefill
False when a zone was refilled, true after changes in zone params.
Definition: zone.h:851
virtual void Flip(const VECTOR2I &aCentre, bool aFlipLeftRight) override
Flip this object, i.e.
Definition: zone.cpp:728
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:434
void SetHatchSmoothingLevel(int aLevel)
Definition: zone.h:283
bool m_doNotAllowTracks
Definition: zone.h:826
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
Definition: zone.h:194
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: zone.cpp:236
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:260
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition: zone.h:713
LSET m_fillFlags
Temp variables used while filling.
Definition: zone.h:892
SHAPE_POLY_SET * Outline()
Definition: zone.h:325
bool m_doNotAllowPads
Definition: zone.h:827
ZONE(BOARD_ITEM_CONTAINER *parent)
Definition: zone.cpp:45
void Move(const VECTOR2I &offset) override
Move the outlines.
Definition: zone.cpp:662
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
Definition: zone.cpp:1093
SHAPE_POLY_SET * m_Poly
Outline of the zone.
Definition: zone.h:795
TEARDROP_TYPE m_teardropType
Definition: zone.h:819
~ZONE()
Definition: zone.cpp:89
long long int GetMinIslandArea() const
Definition: zone.h:716
int m_hatchSmoothingLevel
Definition: zone.h:867
int GetLocalClearance() const
Definition: zone.h:159
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:802
void SetIsRuleArea(bool aEnable)
Definition: zone.h:706
int m_ZoneClearance
Definition: zone.h:831
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
Definition: zone.h:625
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:364
int GetMinThickness() const
Definition: zone.h:258
virtual void swapData(BOARD_ITEM *aImage) override
Definition: zone.cpp:1068
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:441
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
Definition: zone.cpp:760
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Rotate the outlines.
Definition: zone.cpp:717
bool HigherPriority(const ZONE *aOther) const
Definition: zone.cpp:183
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:501
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition: zone.h:180
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: zone.cpp:1062
int m_hatchGap
Definition: zone.h:865
ZONE_CONNECTION GetPadConnection() const
Definition: zone.h:255
void InitDataFromSrcInCopyCtor(const ZONE &aZone)
Copy aZone data to me.
Definition: zone.cpp:99
int GetHatchThickness() const
Definition: zone.h:273
double GetHatchHoleMinArea() const
Definition: zone.h:288
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:540
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:336
int m_hatchBorderAlgorithm
Definition: zone.h:873
bool IsTeardropArea() const
Definition: zone.h:683
std::vector< SEG > m_borderHatchLines
Definition: zone.h:899
VECTOR2I GetPosition() const override
Definition: zone.cpp:230
int GetThermalReliefSpokeWidth() const
Definition: zone.h:202
int GetBorderHatchPitch() const
HatchBorder related methods.
Definition: zone.cpp:874
void SetLocalClearance(int aClearance)
Definition: zone.h:160
void BuildHashValue(PCB_LAYER_ID aLayer)
Build the hash value of m_FilledPolysList, and store it internally in m_filledPolysHash.
Definition: zone.cpp:415
void SetThermalReliefGap(int aThermalReliefGap)
Definition: zone.h:183
EDA_ANGLE GetHatchOrientation() const
Definition: zone.h:279
void SetLayerSet(LSET aLayerSet) override
Definition: zone.cpp:266
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
Definition: zone.cpp:1140
int m_fillVersion
Definition: zone.h:833
const VECTOR2I & GetCornerPosition(int aCornerIndex) const
Definition: zone.h:543
bool GetDoNotAllowFootprints() const
Definition: zone.h:704
ZONE_FILL_MODE GetFillMode() const
Definition: zone.h:181
double m_hatchHoleMinArea
Definition: zone.h:872
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:700
void SetBorderHatchPitch(int aPitch)
Set the hatch pitch parameter for the zone.
Definition: zone.cpp:895
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:1105
int GetHatchGap() const
Definition: zone.h:276
double CalculateOutlineArea()
Compute the area of the zone outline (not the filled area).
Definition: zone.cpp:1311
void SetHatchHoleMinArea(double aPct)
Definition: zone.h:289
unsigned m_priority
Definition: zone.h:808
bool IsConflicting() const
For rule areas which exclude footprints (and therefore participate in courtyard conflicts during move...
Definition: zone.cpp:224
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:895
ISLAND_REMOVAL_MODE m_islandRemovalMode
Definition: zone.h:835
bool m_isFilled
True when a zone was filled, false after deleting the filled areas.
Definition: zone.h:844
double GetHatchSmoothingValue() const
Definition: zone.h:285
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:806
void MoveEdge(const VECTOR2I &offset, int aEdge)
Move the outline Edge.
Definition: zone.cpp:702
int GetHatchSmoothingLevel() const
Definition: zone.h:282
unsigned int GetCornerRadius() const
Definition: zone.h:654
int GetCornerSmoothingType() const
Definition: zone.h:650
int m_thermalReliefGap
Definition: zone.h:853
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: zone.cpp:309
bool IsOnCopperLayer() const override
Definition: zone.cpp:254
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
Definition: zone.cpp:1288
int m_hatchThickness
Definition: zone.h:864
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:1358
void SetAssignedPriority(unsigned aPriority)
Definition: zone.h:114
double m_area
Definition: zone.h:904
unsigned int m_cornerRadius
Definition: zone.h:797
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition: zone.h:256
void SetZoneName(const wxString &aName)
Definition: zone.h:132
void UnHatchBorder()
Clear the zone's hatch.
Definition: zone.cpp:901
void SetIslandRemovalMode(ISLAND_REMOVAL_MODE aRemove)
Definition: zone.h:714
PCB_LAYER_ID GetFirstLayer() const
Definition: zone.cpp:245
void SetMinIslandArea(long long int aArea)
Definition: zone.h:717
ZONE_CONNECTION m_PadConnection
Definition: zone.h:830
bool operator==(const BOARD_ITEM &aOther) const override
Definition: zone.cpp:1395
int GetThermalReliefGap() const
Definition: zone.h:191
void SetHatchGap(int aStep)
Definition: zone.h:277
static int GetDefaultHatchPitch()
Definition: zone.cpp:1056
unsigned GetAssignedPriority() const
Definition: zone.h:119
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition: zone.h:503
bool SameNet(const ZONE *aOther) const
Definition: zone.cpp:200
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:1349
ZONE_BORDER_DISPLAY_STYLE m_borderStyle
Definition: zone.h:897
long long int m_minIslandArea
When island removal mode is set to AREA, islands below this area will be removed.
Definition: zone.h:841
#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:148
bool IsCopperLayer(int aLayerId)
Tests whether a layer is a copper layer.
Definition: layer_ids.h:879
@ LAYER_CONFLICTS_SHADOW
shadow layer for items flagged conficting
Definition: layer_ids.h:244
@ LAYER_FOOTPRINTS_FR
show footprints on front
Definition: layer_ids.h:211
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored)
Definition: layer_ids.h:234
@ LAYER_ZONE_START
Virtual layers for stacking zones and tracks on a given copper layer.
Definition: layer_ids.h:256
@ LAYER_FOOTPRINTS_BK
show footprints on back
Definition: layer_ids.h:212
PCB_LAYER_ID
A quick note on layer IDs:
Definition: layer_ids.h:60
@ B_Cu
Definition: layer_ids.h:96
@ 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:424
#define TYPE_HASH(x)
Definition: property.h:67
#define IMPLEMENT_ENUM_TO_WXANY(type)
Definition: property.h:753
#define NO_SETTER(owner, type)
Definition: property.h:764
#define REGISTER_TYPE(x)
Definition: property_mgr.h:366
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:89
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:105
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:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588
static SHAPE_POLY_SET g_nullPoly
Definition: zone.cpp:403
bool sortEndsByDescendingX(const VECTOR2I &ref, const VECTOR2I &tst)
Definition: zone.cpp:909
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:46
#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