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