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