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