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 The 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, see <https://www.gnu.org/licenses/>.
20 */
21
22#include <advanced_config.h>
23#include <bitmaps.h>
25#include <geometry/shape_null.h>
26#include <pcb_edit_frame.h>
27#include <pcb_screen.h>
28#include <board.h>
30#include <lset.h>
31#include <pad.h>
32#include <zone.h>
33#include <footprint.h>
34#include <string_utils.h>
36#include <properties/property.h>
40#include <trigo.h>
41#include <i18n_utility.h>
42#include <mutex>
43#include <magic_enum.hpp>
44
45#include <google/protobuf/any.pb.h>
46#include <api/api_enums.h>
47#include <api/api_utils.h>
48#include <api/api_pcb_utils.h>
49#include <api/board/board_types.pb.h>
50
51
54 m_Poly( nullptr ),
55 m_cornerRadius( 0 ),
56 m_priority( 0 ),
57 m_isRuleArea( false ),
62 m_ZoneClearance( 0 ),
65 m_isFilled( false ),
70 m_hatchGap( 0 ),
74 m_area( 0.0 ),
75 m_outlinearea( 0.0 )
76{
77 m_Poly = new SHAPE_POLY_SET(); // Outlines
78 SetLocalFlags( 0 ); // flags temporary used in zone calculations
79 m_fillVersion = 5; // set the "old" way to build filled polygon areas (< 6.0.x)
80
81 if( GetParentFootprint() )
82 SetIsRuleArea( true ); // Zones living in footprints have the rule area option
83
84 if( aParent->GetBoard() )
85 aParent->GetBoard()->GetDesignSettings().GetDefaultZoneSettings().ExportSetting( *this, false );
86 else
87 ZONE_SETTINGS().ExportSetting( *this, false );
88
89 m_needRefill = false; // True only after edits.
90}
91
92
93ZONE::ZONE( const ZONE& aZone ) :
94 BOARD_CONNECTED_ITEM( aZone ),
95 m_Poly( nullptr )
96{
98}
99
100
101ZONE& ZONE::operator=( const ZONE& aOther )
102{
104
106
107 return *this;
108}
109
110
111void ZONE::CopyFrom( const BOARD_ITEM* aOther )
112{
113 wxCHECK( aOther && aOther->Type() == PCB_ZONE_T, /* void */ );
114 *this = *static_cast<const ZONE*>( aOther );
115}
116
117
119{
120 delete m_Poly;
121}
122
123
125{
126 // members are expected non initialize in this.
127 // InitDataFromSrcInCopyCtor() is expected to be called only from a copy constructor.
128
129 // Copy only useful EDA_ITEM flags:
130 m_flags = aZone.m_flags;
132
133 // Replace the outlines for aZone outlines.
134 delete m_Poly;
135 m_Poly = new SHAPE_POLY_SET( *aZone.m_Poly );
136
139 m_zoneName = aZone.m_zoneName;
140 m_priority = aZone.m_priority;
145
146 m_fillMode = aZone.m_fillMode; // solid vs. hatched
147
148 if( aLayer == UNDEFINED_LAYER )
149 SetLayerSet( aZone.GetLayerSet() );
150 else
151 SetLayerSet( { aLayer } );
152
158
160 m_ZoneClearance = aZone.m_ZoneClearance; // clearance value
165
166 m_isFilled = aZone.m_isFilled;
167 m_needRefill = aZone.m_needRefill.load();
169
172
174 m_hatchGap = aZone.m_hatchGap;
181
182 aZone.GetLayerSet().RunOnLayers(
183 [&]( PCB_LAYER_ID layer )
184 {
185 if( aLayer != UNDEFINED_LAYER && aLayer != layer )
186 return;
187
188 std::shared_ptr<SHAPE_POLY_SET> fill = aZone.m_FilledPolysList.at( layer );
189
190 if( fill )
191 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>( *fill );
192 else
193 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
194
195 m_filledPolysHash[layer] = aZone.m_filledPolysHash.at( layer );
196 m_insulatedIslands[layer] = aZone.m_insulatedIslands.at( layer );
197 } );
198
200
204
205 SetLocalFlags( aZone.GetLocalFlags() );
206
207 m_netinfo = aZone.m_netinfo;
208 m_area = aZone.m_area;
210
211 // Fresh outline; lock-free bbox cache starts invalid.
212 m_bboxCacheTimeStamp.store( -1, std::memory_order_relaxed );
213}
214
215
217{
218 return new ZONE( *this );
219}
220
221
223{
224 ZONE* clone = new ZONE( BOARD_ITEM::GetParent() );
225 clone->InitDataFromSrcInCopyCtor( *this, aLayer );
226 return clone;
227}
228
229
230BOARD_ITEM* ZONE::Duplicate( bool addToParentGroup, BOARD_COMMIT* aCommit ) const
231{
232 BOARD_ITEM* dupe = BOARD_ITEM::Duplicate( addToParentGroup, aCommit );
233
234 if( const BOARD* board = GetBoard() )
235 {
236 ZONE* newZone = static_cast<ZONE*>( dupe );
237
238 // Give the copy its own name so it does not collide with the original (issue 23131)
239 if( !newZone->GetZoneName().IsEmpty() )
240 newZone->SetZoneName( board->GetUniqueZoneName( newZone->GetZoneName(), newZone ) );
241 }
242
243 return dupe;
244}
245
246
247void ZONE::Serialize( google::protobuf::Any& aContainer ) const
248{
249 using namespace kiapi::board;
250 types::Zone zone;
252
253 zone.mutable_id()->set_value( m_Uuid.AsStdString() );
254 PackLayerSet( *zone.mutable_layers(), GetLayerSet() );
255
256 if( m_isRuleArea )
257 zone.set_type( types::ZT_RULE_AREA );
259 zone.set_type( types::ZT_TEARDROP );
260 else if( IsOnCopperLayer() )
261 zone.set_type( types::ZT_COPPER );
262 else
263 zone.set_type( types::ZT_GRAPHICAL );
264
265 kiapi::common::PackPolySet( *zone.mutable_outline(), *m_Poly );
266
267 zone.set_name( m_zoneName.ToUTF8() );
268 zone.set_priority( m_priority );
269 zone.set_filled( m_isFilled );
270
271 if( FOOTPRINT* parent = GetParentFootprint() )
272 zone.mutable_parent()->set_value( parent->m_Uuid.AsStdString() );
273 else if( const BOARD* board = GetBoard() )
274 zone.mutable_parent()->set_value( board->m_Uuid.AsStdString() );
275
276 if( m_isRuleArea )
277 {
278 types::RuleAreaSettings* ra = zone.mutable_rule_area_settings();
279 ra->set_keepout_copper( m_doNotAllowZoneFills );
280 ra->set_keepout_footprints( m_doNotAllowFootprints );
281 ra->set_keepout_pads( m_doNotAllowPads );
282 ra->set_keepout_tracks( m_doNotAllowTracks );
283 ra->set_keepout_vias( m_doNotAllowVias );
284
285 ra->set_placement_enabled( m_placementAreaEnabled );
286 ra->set_placement_source( m_placementAreaSource.ToUTF8() );
287 ra->set_placement_source_type( ToProtoEnum<PLACEMENT_SOURCE_T,
288 types::PlacementRuleSourceType>( m_placementAreaSourceType ) );
289 }
290 else
291 {
292 types::CopperZoneSettings* cu = zone.mutable_copper_settings();
293 cu->mutable_connection()->set_zone_connection(
295
296 types::ThermalSpokeSettings* thermals = cu->mutable_connection()->mutable_thermal_spokes();
297 thermals->mutable_width()->set_value_nm( m_thermalReliefSpokeWidth );
298 thermals->mutable_gap()->set_value_nm( m_thermalReliefGap );
299 // n.b. zones don't currently have an overall thermal angle override
300
301 cu->mutable_clearance()->set_value_nm( m_ZoneClearance );
302 cu->mutable_min_thickness()->set_value_nm( m_ZoneMinThickness );
303 cu->set_island_mode(
305 cu->set_min_island_area( m_minIslandArea );
307
308 cu->set_corner_smoothing(
310
311 if( m_cornerRadius != 0 )
312 cu->mutable_corner_radius()->set_value_nm( m_cornerRadius );
313
314 types::HatchFillSettings* hatch = cu->mutable_hatch_settings();
315 hatch->mutable_thickness()->set_value_nm( m_hatchThickness );
316 hatch->mutable_gap()->set_value_nm( m_hatchGap );
317 hatch->mutable_orientation()->set_value_degrees( m_hatchOrientation.GetAngle().AsDegrees() );
318 hatch->set_hatch_smoothing_ratio( m_hatchSmoothingValue );
319 hatch->set_hatch_hole_min_area_ratio( m_hatchHoleMinArea );
320
321 switch( m_hatchBorderAlgorithm )
322 {
323 default:
324 case 0: hatch->set_border_mode( types::ZHFBM_USE_MIN_ZONE_THICKNESS ); break;
325 case 1: hatch->set_border_mode( types::ZHFBM_USE_HATCH_THICKNESS ); break;
326 }
327
328 PackNet( cu->mutable_net() );
329 cu->mutable_teardrop()->set_type(
331
332 types::ThievingFillSettings* thieving = cu->mutable_thieving_settings();
333 thieving->set_pattern(
335 thieving->mutable_element_size()->set_value_nm( m_thievingSettings.element_size );
336 thieving->mutable_gap()->set_value_nm( m_thievingSettings.gap );
337 thieving->mutable_line_width()->set_value_nm( m_thievingSettings.line_width );
338 thieving->set_stagger( m_thievingSettings.stagger );
339 thieving->mutable_orientation()->set_value_degrees( m_thievingSettings.orientation.GetAngle().AsDegrees() );
340 }
341
342 for( const auto& [layer, shape] : m_FilledPolysList )
343 {
344 types::ZoneFilledPolygons* filledLayer = zone.add_filled_polygons();
345 filledLayer->set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
346 kiapi::common::PackPolySet( *filledLayer->mutable_shapes(), *shape );
347 }
348
349 for( const auto& [layer, properties] : m_layerProperties )
350 {
351 types::ZoneLayerProperties* layerProperties = zone.add_layer_properties();
352 layerProperties->set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
353
354 if( properties.hatching_offset.has_value() )
355 {
356 PackVector2( *layerProperties->mutable_hatching_offset(),
357 properties.hatching_offset.value() );
358 }
359 }
360
361 zone.mutable_border()->set_style(
363 zone.mutable_border()->mutable_pitch()->set_value_nm( m_borderHatchPitch );
364
365 kiapi::common::PackCustomProperties( zone.mutable_custom_properties(), *this );
366 aContainer.PackFrom( zone );
367}
368
369
370bool ZONE::Deserialize( const google::protobuf::Any& aContainer )
371{
372 using namespace kiapi::board;
373 types::Zone zone;
375
376 if( !aContainer.UnpackTo( &zone ) )
377 return false;
378
379 SetUuidDirect( KIID( zone.id().value() ) );
380 SetLayerSet( UnpackLayerSet( zone.layers() ) );
381 SetAssignedPriority( zone.priority() );
382 SetZoneName( wxString::FromUTF8( zone.name() ) );
383 kiapi::common::UnpackCustomProperties( zone.custom_properties(), *this );
384
385 if( zone.type() == types::ZoneType::ZT_RULE_AREA )
386 m_isRuleArea = true;
387
388 if( !m_Poly )
390
391 *m_Poly = kiapi::common::UnpackPolySet( zone.outline() );
392
393 if( m_Poly->OutlineCount() == 0 )
394 return false;
395
396 if( m_isRuleArea )
397 {
398 const types::RuleAreaSettings& ra = zone.rule_area_settings();
399 m_doNotAllowZoneFills = ra.keepout_copper();
400 m_doNotAllowFootprints = ra.keepout_footprints();
401 m_doNotAllowPads = ra.keepout_pads();
402 m_doNotAllowTracks = ra.keepout_tracks();
403 m_doNotAllowVias = ra.keepout_vias();
404
405 m_placementAreaEnabled = ra.placement_enabled();
406 m_placementAreaSource = wxString::FromUTF8( ra.placement_source() );
407 m_placementAreaSourceType = FromProtoEnum<PLACEMENT_SOURCE_T>( ra.placement_source_type() );
408 }
409 else
410 {
411 const types::CopperZoneSettings& cu = zone.copper_settings();
412 m_PadConnection = FromProtoEnum<ZONE_CONNECTION>( cu.connection().zone_connection() );
413 m_thermalReliefSpokeWidth = cu.connection().thermal_spokes().width().value_nm();
414 m_thermalReliefGap = cu.connection().thermal_spokes().gap().value_nm();
415 m_ZoneClearance = cu.clearance().value_nm();
416 m_ZoneMinThickness = cu.min_thickness().value_nm();
418 m_minIslandArea = cu.min_island_area();
419 // Route through SetFillMode so the thieving single-layer / net-less invariants
420 // are enforced on protobuf imports — a direct m_fillMode assignment would leave
421 // the multi-layer set unpacked at line 355 in place for ZFM_COPPER_THIEVING.
422 SetFillMode( FromProtoEnum<ZONE_FILL_MODE>( cu.fill_mode() ) );
423
425
426 if( cu.has_corner_radius() )
427 SetCornerRadius( cu.corner_radius().value_nm() );
428 else
429 SetCornerRadius( 0 );
430
431 m_hatchThickness = cu.hatch_settings().thickness().value_nm();
432 m_hatchGap = cu.hatch_settings().gap().value_nm();
433 m_hatchOrientation = EDA_ANGLE( cu.hatch_settings().orientation().value_degrees(), DEGREES_T );
434 m_hatchSmoothingValue = cu.hatch_settings().hatch_smoothing_ratio();
435 m_hatchHoleMinArea = cu.hatch_settings().hatch_hole_min_area_ratio();
436
437 switch( cu.hatch_settings().border_mode() )
438 {
439 default:
440 case types::ZHFBM_USE_MIN_ZONE_THICKNESS: m_hatchBorderAlgorithm = 0; break;
441 case types::ZHFBM_USE_HATCH_THICKNESS: m_hatchBorderAlgorithm = 1; break;
442 }
443
444 UnpackNet( cu.net() );
445 m_teardropType = FromProtoEnum<TEARDROP_TYPE>( cu.teardrop().type() );
446
447 if( cu.has_thieving_settings() )
448 {
449 const types::ThievingFillSettings& thieving = cu.thieving_settings();
450 m_thievingSettings.pattern =
451 FromProtoEnum<THIEVING_PATTERN>( thieving.pattern() );
452
453 auto assignIfPositive = []( int aProtoValue, int& aTarget )
454 {
455 if( aProtoValue > 0 )
456 aTarget = aProtoValue;
457 };
458
459 assignIfPositive( thieving.element_size().value_nm(), m_thievingSettings.element_size );
460 assignIfPositive( thieving.gap().value_nm(), m_thievingSettings.gap );
461 assignIfPositive( thieving.line_width().value_nm(), m_thievingSettings.line_width );
462
463 m_thievingSettings.stagger = thieving.stagger();
464 m_thievingSettings.orientation =
465 EDA_ANGLE( thieving.orientation().value_degrees(), DEGREES_T );
466 }
467
468 for( const auto& properties : zone.layer_properties() )
469 {
470 PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( properties.layer() );
471
472 ZONE_LAYER_PROPERTIES layerProperties;
473
474 if( properties.has_hatching_offset() )
475 layerProperties.hatching_offset = UnpackVector2( properties.hatching_offset() );
476
477 m_layerProperties[layer] = layerProperties;
478 }
479 }
480
482 m_borderHatchPitch = zone.border().pitch().value_nm();
483
484 if( zone.filled() )
485 {
486 SetIsFilled( true );
487 SetNeedRefill( false );
488
489 for( const types::ZoneFilledPolygons& fillLayer : zone.filled_polygons() )
490 {
491 PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( fillLayer.layer() );
492 SHAPE_POLY_SET shape = kiapi::common::UnpackPolySet( fillLayer.shapes() );
493 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>( shape );
494 }
495 }
496 else
497 {
498 UnFill();
499 }
500
501
502 HatchBorder();
503
504 return true;
505}
506
507
508bool ZONE::HigherPriority( const ZONE* aOther ) const
509{
510 // Teardrops are always higher priority than regular zones, so if one zone is a teardrop
511 // and the other is not, then return higher priority as the teardrop
513 return static_cast<int>( m_teardropType ) > static_cast<int>( aOther->m_teardropType );
514
515 if( m_priority != aOther->m_priority )
516 return m_priority > aOther->m_priority;
517
518 return m_Uuid > aOther->m_Uuid;
519}
520
521
522bool ZONE::SameNet( const ZONE* aOther ) const
523{
524 return GetNetCode() == aOther->GetNetCode();
525}
526
527
529{
530 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
531
532 return unFillLocked();
533}
534
535
537{
538 bool change = false;
539
540 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
541 {
542 change |= !pair.second->IsEmpty();
543 m_insulatedIslands[pair.first].clear();
544
545 // Replace the shared_ptr with a new empty object rather than clearing the existing one.
546 // This ensures that any CN_ZONE_LAYERs holding shared_ptr copies still have valid data
547 // (the old, now orphaned SHAPE_POLY_SET) while we get a fresh container.
548 pair.second = std::make_shared<SHAPE_POLY_SET>();
549 }
550
551 m_isFilled = false;
552 m_fillFlags.reset();
553
554 return change;
555}
556
557
559{
560 return HasFlag( COURTYARD_CONFLICT );
561}
562
563
565{
566 if( m_Poly->OutlineCount() == 0 || m_Poly->TotalVertices() == 0 )
567 return VECTOR2I( 0, 0 );
568
569 return GetCornerPosition( 0 );
570}
571
572
574{
575 std::lock_guard<std::mutex> lock( m_layerSetMutex );
576
577 if( m_layerSet.count() == 1 )
578 {
579 // GetFirstLayer would try to acquire the mutex again, so inline its logic here
580 if( m_layerSet.count() == 0 )
581 return UNDEFINED_LAYER;
582
583 const LSEQ uiLayers = m_layerSet.UIOrder();
584
585 if( uiLayers.size() )
586 return uiLayers[0];
587
588 return m_layerSet.Seq()[0];
589 }
590
591 return UNDEFINED_LAYER;
592}
593
594
596{
597 std::lock_guard<std::mutex> lock( m_layerSetMutex );
598
599 if( m_layerSet.count() == 0 )
600 return UNDEFINED_LAYER;
601
602 const LSEQ uiLayers = m_layerSet.UIOrder();
603
604 // This can't use m_layerSet.count() because it's possible to have a zone on
605 // a rescue layer that is not in the UI order.
606 if( uiLayers.size() )
607 return uiLayers[0];
608
609 // If it's not in the UI set at all, just return the first layer in the set.
610 // (we know the count > 0)
611 return m_layerSet.Seq()[0];
612}
613
614
616{
617 std::lock_guard<std::mutex> lock( m_layerSetMutex );
618 return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
619}
620
621
622bool ZONE::SetNetCode( int aNetCode, bool aNoAssert )
623{
624 if( IsCopperThieving() )
625 aNetCode = 0;
626
627 return BOARD_CONNECTED_ITEM::SetNetCode( aNetCode, aNoAssert );
628}
629
630
631void ZONE::SetNet( NETINFO_ITEM* aNetInfo )
632{
633 if( IsCopperThieving() )
634 aNetInfo = nullptr;
635
637}
638
639
641{
642 SetLayerSet( LSET( { aLayer } ) );
643}
644
645
647{
648 if( m_fillMode == aFillMode )
649 return;
650
651 SetNeedRefill( true );
652 m_fillMode = aFillMode;
653
654 // Thieving zones are net-less and single-layer; clamp on transition so a
655 // multi-layer netted POLYGONS zone converted via the property panel or a
656 // load-time SetLayerSet-then-SetFillMode sequence cannot keep stale state.
658 {
661 }
662}
663
664
665void ZONE::SetLayerSet( const LSET& aLayerSet )
666{
667 if( aLayerSet.count() == 0 )
668 return;
669
670 // Thieving zones are single-layer; clamp here so direct callers cannot violate
671 // the invariant. UIOrder().front() matches GetFirstLayer().
672 const LSET effectiveSet = ( IsCopperThieving() && aLayerSet.count() > 1 )
673 ? LSET( { aLayerSet.UIOrder().front() } )
674 : aLayerSet;
675
676 std::scoped_lock lock( m_layerSetMutex, m_filledPolysListMutex );
677
678 if( m_layerSet != effectiveSet )
679 {
680 SetNeedRefill( true );
681
682 unFillLocked();
683
684 m_FilledPolysList.clear();
685 m_filledPolysHash.clear();
686 m_insulatedIslands.clear();
687
688 effectiveSet.RunOnLayers(
689 [&]( PCB_LAYER_ID layer )
690 {
691 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
692 m_filledPolysHash[layer] = {};
693 m_insulatedIslands[layer] = {};
694 } );
695
696 std::erase_if( m_layerProperties,
697 [&]( const auto& item )
698 {
699 return !effectiveSet.Contains( item.first );
700 } );
701 }
702
703 m_layerSet = effectiveSet;
704}
705
706
707void ZONE::SetLayerProperties( const std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& aOther )
708{
709 m_layerProperties = aOther;
710}
711
712
713std::vector<int> ZONE::ViewGetLayers() const
714{
715 std::lock_guard<std::mutex> lock( m_layerSetMutex );
716
717 std::vector<int> layers;
718 layers.reserve( 2 * m_layerSet.count() + 1 );
719
720 m_layerSet.RunOnLayers(
721 [&]( PCB_LAYER_ID layer )
722 {
723 layers.push_back( layer );
724 layers.push_back( layer + static_cast<int>( LAYER_ZONE_START ) );
725 } );
726
727 layers.push_back( LAYER_CONFLICTS_SHADOW );
728
729 return layers;
730}
731
732
733double ZONE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
734{
735 if( !aView )
736 return LOD_SHOW;
737
738 if( !aView->IsLayerVisibleCached( LAYER_ZONES ) )
739 return LOD_HIDE;
740
741 if( FOOTPRINT* parentFP = GetParentFootprint() )
742 {
743 const LSET zl = GetLayerSet();
744 bool onFront = ( zl & LSET::FrontMask() ).any();
745 bool onBack = ( zl & LSET::BackMask() ).any();
746
747 if( !onFront && !onBack )
748 {
749 onFront = parentFP->GetLayer() == F_Cu;
750 onBack = parentFP->GetLayer() == B_Cu;
751 }
752
753 const bool frHidden = !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_FR );
754 const bool bkHidden = !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_BK );
755
756 if( onFront && !onBack && frHidden )
757 return LOD_HIDE;
758
759 if( onBack && !onFront && bkHidden )
760 return LOD_HIDE;
761
762 if( onFront && onBack && frHidden && bkHidden )
763 return LOD_HIDE;
764 }
765
766 // Other layers are shown without any conditions
767 return LOD_SHOW;
768}
769
770
771bool ZONE::IsOnLayer( PCB_LAYER_ID aLayer ) const
772{
773 std::lock_guard<std::mutex> lock( m_layerSetMutex );
774 return m_layerSet.test( aLayer );
775}
776
777
779{
780 if( GetParentFootprint() )
781 return GetBoardOutline().BBox();
782
783 return m_Poly->BBox();
784}
785
786
788{
789 if( const BOARD* board = GetBoard() )
790 {
791 // Lock-free fast path, valid while the board timestamp matches what we cached for.
792 // Skips the caches mutex that otherwise serializes every fill worker.
793 if( m_bboxCacheTimeStamp.load( std::memory_order_acquire ) == board->GetTimeStamp() )
794 return m_bboxCache;
795
796 std::unordered_map<const ZONE*, BOX2I>& cache = board->m_ZoneBBoxCache;
797
798 {
799 std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
800
801 auto cacheIter = cache.find( this );
802
803 if( cacheIter != cache.end() )
804 return cacheIter->second;
805 }
806
807 BOX2I bbox = computeBoundingBox();
808
809 {
810 std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
811 cache[ this ] = bbox;
812 }
813
814 return bbox;
815 }
816
817 return computeBoundingBox();
818}
819
820
822{
823 if( const BOARD* board = GetBoard() )
824 {
825 std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
826 board->m_ZoneBBoxCache.erase( this );
827 }
828
829 m_bboxCacheTimeStamp.store( -1, std::memory_order_release );
830}
831
832
834{
835 // Footprint zone bounding boxes are derived through the parent transform
837 SetNeedRefill( true );
838 UnFill();
839}
840
841
843{
844 const BOARD* board = GetBoard();
845 BOX2I bbox = computeBoundingBox();
846
847 if( board )
848 {
849 // Board cache, for callers that read it directly.
850 {
851 std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
852 board->m_ZoneBBoxCache[this] = bbox;
853 }
854
855 // Per-zone lock-free copy. Single-threaded per zone, so box-before-timestamp (release)
856 // suffices for the acquiring reader in GetBoundingBox().
857 m_bboxCache = bbox;
858 m_bboxCacheTimeStamp.store( board->GetTimeStamp(), std::memory_order_release );
859 }
860}
861
862
863int ZONE::GetThermalReliefGap( PAD* aPad, wxString* aSource ) const
864{
865 if( aPad->GetLocalThermalGapOverride() == 0 )
866 {
867 if( aSource )
868 *aSource = _( "zone" );
869
870 return m_thermalReliefGap;
871 }
872
873 return aPad->GetLocalThermalGapOverride( aSource );
874
875}
876
877
878void ZONE::SetCornerRadius( unsigned int aRadius )
879{
880 if( m_cornerRadius != aRadius )
881 SetNeedRefill( true );
882
883 m_cornerRadius = aRadius;
884}
885
886
888
889
891{
892 if( !m_filledPolysHash.count( aLayer ) )
893 return g_nullPoly.GetHash();
894 else
895 return m_filledPolysHash.at( aLayer );
896}
897
898
900{
901 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
902
903 if( !m_FilledPolysList.count( aLayer ) )
904 m_filledPolysHash[aLayer] = g_nullPoly.GetHash();
905 else
906 m_filledPolysHash[aLayer] = m_FilledPolysList.at( aLayer )->GetHash();
907}
908
909
914
915
917{
918 SHAPE_POLY_SET poly;
919
920 if( const FOOTPRINT* fp = GetParentFootprint() )
921 {
922 if( m_Poly )
923 poly = m_Poly->CloneDropTriangulation();
924
925 const TRANSFORM_TRS& xform = fp->GetTransform();
926
927 for( auto it = poly.IterateWithHoles(); it; it++ )
928 poly.SetVertex( it.GetIndex(), xform.Apply( *it ) );
929 }
930 else
931 {
932 if( m_Poly )
933 poly = m_Poly->CloneDropTriangulation();
934 }
935
936 return poly;
937}
938
939
940bool ZONE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
941{
942 // When looking for an "exact" hit aAccuracy will be 0 which works poorly for very thin
943 // lines. Give it a floor.
944 int accuracy = std::max( aAccuracy, pcbIUScale.mmToIU( 0.1 ) );
945
946 return HitTestForCorner( aPosition, accuracy * 2 ) || HitTestForEdge( aPosition, accuracy );
947}
948
949
950bool ZONE::HitTestForCorner( const VECTOR2I& refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
951{
952 VECTOR2I libPos = refPos;
953
954 if( const FOOTPRINT* fp = GetParentFootprint() )
955 libPos = fp->GetTransform().InverseApply( refPos );
956
957 return m_Poly->CollideVertex( libPos, aCornerHit, aAccuracy );
958}
959
960
961bool ZONE::HitTestForEdge( const VECTOR2I& refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
962{
963 VECTOR2I libPos = refPos;
964
965 if( const FOOTPRINT* fp = GetParentFootprint() )
966 libPos = fp->GetTransform().InverseApply( refPos );
967
968 return m_Poly->CollideEdge( libPos, aCornerHit, aAccuracy );
969}
970
971
972bool ZONE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
973{
974 // Calculate bounding box for zone
975 BOX2I bbox = GetBoundingBox();
976 bbox.Normalize();
977
978 BOX2I arect = aRect;
979 arect.Normalize();
980 arect.Inflate( aAccuracy );
981
982 if( aContained )
983 {
984 return arect.Contains( bbox );
985 }
986 else
987 {
988 // Fast test: if aBox is outside the polygon bounding box, rectangles cannot intersect
989 if( !arect.Intersects( bbox ) )
990 return false;
991
992 SHAPE_POLY_SET boardOutline = GetBoardOutline();
993 int count = boardOutline.TotalVertices();
994
995 for( int ii = 0; ii < count; ii++ )
996 {
997 const VECTOR2I& vertex = boardOutline.CVertex( ii );
998 const VECTOR2I& vertexNext = boardOutline.CVertex( ( ii + 1 ) % count );
999
1000 // Test if the point is within the rect
1001 if( arect.Contains( vertex ) )
1002 return true;
1003
1004 // Test if this edge intersects the rect
1005 if( arect.Intersects( vertex, vertexNext ) )
1006 return true;
1007 }
1008
1009 return false;
1010 }
1011}
1012
1013
1014bool ZONE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
1015{
1016 SHAPE_POLY_SET outline = GetBoardOutline();
1017
1018 if( aContained )
1019 {
1020 auto outlineIntersectingSelection =
1021 [&]()
1022 {
1023 for( auto segment = outline.IterateSegments(); segment; segment++ )
1024 {
1025 if( aPoly.Intersects( *segment ) )
1026 return true;
1027 }
1028
1029 return false;
1030 };
1031
1032 // In the case of contained selection, all vertices of the zone outline must be inside
1033 // the selection polygon, so we can check only the first vertex.
1034 auto vertexInsideSelection =
1035 [&]()
1036 {
1037 return aPoly.PointInside( outline.CVertex( 0 ) );
1038 };
1039
1040 return vertexInsideSelection() && !outlineIntersectingSelection();
1041 }
1042 else
1043 {
1044 // Touching selection - check if any segment of the zone contours collides with the
1045 // selection shape.
1046 for( auto segment = outline.IterateSegmentsWithHoles(); segment; segment++ )
1047 {
1048 if( aPoly.PointInside( ( *segment ).A ) )
1049 return true;
1050
1051 if( aPoly.Intersects( *segment ) )
1052 return true;
1053
1054 // Note: aPoly.Collide() could be used instead of two test above, but it is 3x slower.
1055 }
1056
1057 return false;
1058 }
1059}
1060
1061
1062std::optional<int> ZONE::GetLocalClearance() const
1063{
1064 return m_isRuleArea ? 0 : m_ZoneClearance;
1065}
1066
1067
1068bool ZONE::HitTestFilledArea( PCB_LAYER_ID aLayer, const VECTOR2I& aRefPos, int aAccuracy ) const
1069{
1070 // Rule areas have no filled area, but it's generally nice to treat their interior as if it were
1071 // filled so that people don't have to select them by their outline (which is min-width)
1072 if( GetIsRuleArea() )
1073 {
1074 VECTOR2I libPos = aRefPos;
1075
1076 if( const FOOTPRINT* fp = GetParentFootprint() )
1077 libPos = fp->GetTransform().InverseApply( aRefPos );
1078
1079 return m_Poly->Contains( libPos, -1, aAccuracy );
1080 }
1081
1082 std::shared_ptr<SHAPE_POLY_SET> fillPolys;
1083
1084 {
1085 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1086
1087 if( !m_FilledPolysList.count( aLayer ) )
1088 return false;
1089
1090 fillPolys = m_FilledPolysList.at( aLayer );
1091 }
1092
1093 return fillPolys->Contains( aRefPos, -1, aAccuracy );
1094}
1095
1096
1097bool ZONE::HitTestCutout( const VECTOR2I& aRefPos, int* aOutlineIdx, int* aHoleIdx ) const
1098{
1099 VECTOR2I libPos = aRefPos;
1100
1101 if( const FOOTPRINT* fp = GetParentFootprint() )
1102 libPos = fp->GetTransform().InverseApply( aRefPos );
1103
1104 // Iterate over each outline polygon in the zone and then iterate over
1105 // each hole it has to see if the point is in it.
1106 for( int i = 0; i < m_Poly->OutlineCount(); i++ )
1107 {
1108 for( int j = 0; j < m_Poly->HoleCount( i ); j++ )
1109 {
1110 if( m_Poly->Hole( i, j ).PointInside( libPos ) )
1111 {
1112 if( aOutlineIdx )
1113 *aOutlineIdx = i;
1114
1115 if( aHoleIdx )
1116 *aHoleIdx = j;
1117
1118 return true;
1119 }
1120 }
1121 }
1122
1123 return false;
1124}
1125
1126
1127void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1128{
1129 wxString msg = GetFriendlyName();
1130
1131 aList.emplace_back( _( "Type" ), msg );
1132
1133 if( GetIsRuleArea() )
1134 {
1135 msg.Empty();
1136
1137 if( GetDoNotAllowVias() )
1138 AccumulateDescription( msg, _( "No vias" ) );
1139
1140 if( GetDoNotAllowTracks() )
1141 AccumulateDescription( msg, _( "No tracks" ) );
1142
1143 if( GetDoNotAllowPads() )
1144 AccumulateDescription( msg, _( "No pads" ) );
1145
1147 AccumulateDescription( msg, _( "No zone fills" ) );
1148
1150 AccumulateDescription( msg, _( "No footprints" ) );
1151
1152 if( !msg.IsEmpty() )
1153 aList.emplace_back( _( "Restrictions" ), msg );
1154
1156 aList.emplace_back( _( "Placement source" ), UnescapeString( GetPlacementAreaSource() ) );
1157 }
1158 else if( IsOnCopperLayer() )
1159 {
1160 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1161 {
1162 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
1163
1164 aList.emplace_back( _( "Resolved Netclass" ),
1165 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
1166 }
1167
1168 // Display priority level
1169 aList.emplace_back( _( "Priority" ), wxString::Format( wxT( "%d" ), GetAssignedPriority() ) );
1170 }
1171
1172 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1173 {
1174 if( IsLocked() )
1175 aList.emplace_back( _( "Status" ), _( "Locked" ) );
1176 }
1177
1178 LSEQ layers = m_layerSet.Seq();
1179 wxString layerDesc;
1180
1181 if( layers.size() == 1 )
1182 {
1183 layerDesc.Printf( _( "%s" ), GetBoard()->GetLayerName( layers[0] ) );
1184 }
1185 else if (layers.size() == 2 )
1186 {
1187 layerDesc.Printf( _( "%s and %s" ),
1188 GetBoard()->GetLayerName( layers[0] ),
1189 GetBoard()->GetLayerName( layers[1] ) );
1190 }
1191 else if (layers.size() == 3 )
1192 {
1193 layerDesc.Printf( _( "%s, %s and %s" ),
1194 GetBoard()->GetLayerName( layers[0] ),
1195 GetBoard()->GetLayerName( layers[1] ),
1196 GetBoard()->GetLayerName( layers[2] ) );
1197 }
1198 else if( layers.size() > 3 )
1199 {
1200 layerDesc.Printf( _( "%s, %s and %d more" ),
1201 GetBoard()->GetLayerName( layers[0] ),
1202 GetBoard()->GetLayerName( layers[1] ),
1203 static_cast<int>( layers.size() - 2 ) );
1204 }
1205
1206 aList.emplace_back( _( "Layer" ), layerDesc );
1207
1208 if( !m_zoneName.empty() )
1209 aList.emplace_back( _( "Name" ), m_zoneName );
1210
1211 if( !GetIsRuleArea() ) // Show fill mode only for not rule areas
1212 {
1213 switch( m_fillMode )
1214 {
1215 case ZONE_FILL_MODE::POLYGONS: msg = _( "Solid" ); break;
1216 case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break;
1217 default: msg = _( "Unknown" ); break;
1218 }
1219
1220 aList.emplace_back( _( "Fill Mode" ), msg );
1221
1222 aList.emplace_back( _( "Filled Area" ),
1224
1225 wxString source;
1227
1228 if( !source.IsEmpty() )
1229 {
1230 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ), aFrame->MessageTextFromValue( clearance ) ),
1231 wxString::Format( _( "(from %s)" ), source ) );
1232 }
1233 }
1234
1235 int count = 0;
1236
1237 if( GetIsRuleArea() )
1238 {
1239 double outline_area = CalculateOutlineArea();
1240 aList.emplace_back( _( "Outline Area" ),
1241 aFrame->MessageTextFromValue( outline_area, true, EDA_DATA_TYPE::AREA ) );
1242
1243 // No need to determine board vs. library outline. They'll have the same number of points.
1244 const SHAPE_POLY_SET* area_outline = Outline();
1245 count = area_outline->FullPointCount();
1246 }
1247 else if( !m_FilledPolysList.empty() )
1248 {
1249 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& ii: m_FilledPolysList )
1250 count += ii.second->TotalVertices();
1251 }
1252
1253 aList.emplace_back( _( "Corner Count" ), wxString::Format( wxT( "%d" ), count ) );
1254}
1255
1256
1257void ZONE::Move( const VECTOR2I& offset )
1258{
1259 VECTOR2I outlineOffset = offset;
1260
1261 if( const FOOTPRINT* fp = GetParentFootprint() )
1262 {
1263 const TRANSFORM_TRS& xform = fp->GetTransform();
1264 outlineOffset = xform.InverseApply( offset ) - xform.InverseApply( VECTOR2I( 0, 0 ) );
1265 }
1266
1267 m_Poly->Move( outlineOffset );
1268
1269 // Translate existing hatch lines instead of regenerating them. HatchBorder() is expensive
1270 // (O(n*m) segment intersections + point-in-polygon tests) and the hatch pattern is
1271 // invariant under translation.
1272 for( SEG& seg : m_borderHatchLines )
1273 {
1274 seg.A += outlineOffset;
1275 seg.B += outlineOffset;
1276 }
1277
1278 /* move fills */
1279 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1280 pair.second->Move( offset );
1281
1282 /*
1283 * move boundingbox cache
1284 *
1285 * While the cache will get nuked at the conclusion of the operation, we use it for some
1286 * things (such as drawing the parent group) during the move.
1287 */
1288 if( GetBoard() )
1289 {
1290 auto it = GetBoard()->m_ZoneBBoxCache.find( this );
1291
1292 if( it != GetBoard()->m_ZoneBBoxCache.end() )
1293 it->second.Move( offset );
1294 }
1295
1296 // Move doesn't bump the board timestamp, so invalidate the lock-free copy rather than race
1297 // readers by mutating it. GetBoundingBox() falls back to the board cache (moved above).
1298 m_bboxCacheTimeStamp.store( -1, std::memory_order_release );
1299}
1300
1301
1303{
1304 if( GetIsRuleArea() )
1305 return _( "Rule Area" );
1306 else if( IsTeardropArea() )
1307 return _( "Teardrop Area" );
1308 else if( IsOnCopperLayer() )
1309 return _( "Copper Zone" );
1310 else
1311 return _( "Non-copper Zone" );
1312}
1313
1314
1315void ZONE::MoveEdge( const VECTOR2I& offset, int aEdge )
1316{
1317 int next_corner;
1318
1319 if( m_Poly->GetNeighbourIndexes( aEdge, nullptr, &next_corner ) )
1320 {
1321 VECTOR2I libOffset = offset;
1322
1323 if( const FOOTPRINT* fp = GetParentFootprint() )
1324 {
1325 const TRANSFORM_TRS& xform = fp->GetTransform();
1326 libOffset = xform.InverseApply( offset ) - xform.InverseApply( VECTOR2I( 0, 0 ) );
1327 }
1328
1329 m_Poly->SetVertex( aEdge, m_Poly->CVertex( aEdge ) + libOffset );
1330 m_Poly->SetVertex( next_corner, m_Poly->CVertex( next_corner ) + libOffset );
1331 HatchBorder();
1332
1333 SetNeedRefill( true );
1334 }
1335}
1336
1337
1338void ZONE::Rotate( const VECTOR2I& aCentre, const EDA_ANGLE& aAngle )
1339{
1340 VECTOR2I outlineCentre = aCentre;
1341
1342 if( const FOOTPRINT* fp = GetParentFootprint() )
1343 outlineCentre = fp->GetTransform().InverseApply( aCentre );
1344
1345 m_Poly->Rotate( aAngle, outlineCentre );
1347 HatchBorder();
1348
1349 /* rotate filled areas: */
1350 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1351 pair.second->Rotate( aAngle, aCentre );
1352}
1353
1354
1355void ZONE::OnFootprintRescaled( double aRatioX, double aRatioY, double /* aLinearFactor */,
1356 const VECTOR2I& /* aAnchor */, const EDA_ANGLE& /* aParentRotate */ )
1357{
1358 if( aRatioX == 1.0 && aRatioY == 1.0 )
1359 return;
1360
1361 // Zone outline auto-derives from lib storage through the parent transform.
1362 // Just invalidate the fill since geometry-on-screen has changed.
1364 SetNeedRefill( true );
1365 UnFill();
1366}
1367
1368
1369void ZONE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1370{
1371 Mirror( aCentre, aFlipDirection );
1372
1373 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> fillsCopy;
1374
1375 for( auto& [oldLayer, shapePtr] : m_FilledPolysList )
1376 fillsCopy[oldLayer] = *shapePtr;
1377
1378 std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES> layerPropertiesCopy = m_layerProperties;
1379
1380 LSET flipped;
1381
1382 for( PCB_LAYER_ID layer : GetLayerSet() )
1383 flipped.set( GetBoard()->FlipLayer( layer ) );
1384
1385 SetLayerSet( flipped );
1386
1387 for( auto& [oldLayer, properties] : layerPropertiesCopy )
1388 {
1389 PCB_LAYER_ID newLayer = GetBoard()->FlipLayer( oldLayer );
1390 m_layerProperties[newLayer] = properties;
1391 }
1392
1393 for( auto& [oldLayer, shape] : fillsCopy )
1394 {
1395 PCB_LAYER_ID newLayer = GetBoard()->FlipLayer( oldLayer );
1396 SetFilledPolysList( newLayer, shape );
1397 }
1398}
1399
1400
1401void ZONE::Mirror( const VECTOR2I& aMirrorRef, FLIP_DIRECTION aFlipDirection )
1402{
1403 VECTOR2I outlineRef = aMirrorRef;
1404
1405 if( const FOOTPRINT* fp = GetParentFootprint() )
1406 outlineRef = fp->GetTransform().InverseApply( aMirrorRef );
1407
1408 m_Poly->Mirror( outlineRef, aFlipDirection );
1410
1411 HatchBorder();
1412
1413 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1414 pair.second->Mirror( aMirrorRef, aFlipDirection );
1415}
1416
1417
1418void ZONE::RemoveCutout( int aOutlineIdx, int aHoleIdx )
1419{
1420 // Ensure the requested cutout is valid
1421 if( m_Poly->OutlineCount() < aOutlineIdx || m_Poly->HoleCount( aOutlineIdx ) < aHoleIdx )
1422 return;
1423
1424 SHAPE_POLY_SET cutPoly( m_Poly->Hole( aOutlineIdx, aHoleIdx ) );
1425
1426 // Add the cutout back to the zone
1427 m_Poly->BooleanAdd( cutPoly );
1428
1429 SetNeedRefill( true );
1430}
1431
1432
1433void ZONE::AddPolygon( const SHAPE_LINE_CHAIN& aPolygon )
1434{
1435 wxASSERT( aPolygon.IsClosed() );
1436
1437 // Add the outline as a new polygon in the polygon set
1438 if( m_Poly->OutlineCount() == 0 )
1439 m_Poly->AddOutline( aPolygon );
1440 else
1441 m_Poly->AddHole( aPolygon );
1442
1443 SetNeedRefill( true );
1444}
1445
1446
1447void ZONE::AddPolygon( std::vector<VECTOR2I>& aPolygon )
1448{
1449 if( aPolygon.empty() )
1450 return;
1451
1452 SHAPE_LINE_CHAIN outline;
1453
1454 // Create an outline and populate it with the points of aPolygon
1455 for( const VECTOR2I& pt : aPolygon )
1456 outline.Append( pt );
1457
1458 outline.SetClosed( true );
1459
1460 AddPolygon( outline );
1461}
1462
1463
1464bool ZONE::AppendCorner( const VECTOR2I& aPosition, int aHoleIdx, bool aAllowDuplication )
1465{
1466 // Ensure the main outline exists:
1467 if( m_Poly->OutlineCount() == 0 )
1468 m_Poly->NewOutline();
1469
1470 // If aHoleIdx >= 0, the corner musty be added to the hole, index aHoleIdx.
1471 // (remember: the index of the first hole is 0)
1472 // Return error if it does not exist.
1473 if( aHoleIdx >= m_Poly->HoleCount( 0 ) )
1474 return false;
1475
1476 m_Poly->Append( aPosition.x, aPosition.y, -1, aHoleIdx, aAllowDuplication );
1477
1478 SetNeedRefill( true );
1479
1480 return true;
1481}
1482
1483
1484wxString ZONE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1485{
1486 LSEQ layers = m_layerSet.Seq();
1487 wxString layerDesc;
1488
1489 auto layerName =
1490 [this]( PCB_LAYER_ID aLayer ) -> wxString
1491 {
1492 if( const BOARD* board = GetBoard() )
1493 return board->GetLayerName( aLayer );
1494
1495 return BOARD::GetStandardLayerName( aLayer );
1496 };
1497
1498 if( layers.size() == 1 )
1499 {
1500 layerDesc.Printf( _( "on %s" ), layerName( layers[0] ) );
1501 }
1502 else if (layers.size() == 2 )
1503 {
1504 layerDesc.Printf( _( "on %s and %s" ),
1505 layerName( layers[0] ),
1506 layerName( layers[1] ) );
1507 }
1508 else if (layers.size() == 3 )
1509 {
1510 layerDesc.Printf( _( "on %s, %s and %s" ),
1511 layerName( layers[0] ),
1512 layerName( layers[1] ),
1513 layerName( layers[2] ) );
1514 }
1515 else if( layers.size() > 3 )
1516 {
1517 layerDesc.Printf( _( "on %s, %s and %zu more" ),
1518 layerName( layers[0] ),
1519 layerName( layers[1] ),
1520 layers.size() - 2 );
1521 }
1522
1523 if( GetIsRuleArea() )
1524 {
1525 if( GetZoneName().IsEmpty() )
1526 {
1527 return wxString::Format( _( "Rule Area %s" ), layerDesc );
1528 }
1529 else
1530 {
1531 return wxString::Format( _( "Rule area '%s' %s" ),
1532 GetZoneName(),
1533 layerDesc );
1534 }
1535 }
1536 else if( IsTeardropArea() )
1537 {
1538 return wxString::Format( _( "Teardrop %s %s" ),
1539 GetNetnameMsg(),
1540 layerDesc );
1541 }
1542 else
1543 {
1544 if( GetZoneName().IsEmpty() )
1545 {
1546 return wxString::Format( _( "Zone %s %s, priority %d" ),
1547 GetNetnameMsg(),
1548 layerDesc,
1550 }
1551 else
1552 {
1553 return wxString::Format( _( "Zone '%s' %s %s, priority %d" ),
1554 GetZoneName(),
1555 GetNetnameMsg(),
1556 layerDesc,
1558 }
1559 }
1560}
1561
1562
1563void ZONE::SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch,
1564 bool aRebuildBorderHatch )
1565{
1566 aBorderHatchPitch = std::max( aBorderHatchPitch, pcbIUScale.mmToIU( ZONE_BORDER_HATCH_MINDIST_MM ) );
1567 aBorderHatchPitch = std::min( aBorderHatchPitch, pcbIUScale.mmToIU( ZONE_BORDER_HATCH_MAXDIST_MM ) );
1568 SetBorderHatchPitch( aBorderHatchPitch );
1569 m_borderStyle = aBorderHatchStyle;
1570
1571 if( aRebuildBorderHatch )
1572 HatchBorder();
1573}
1574
1575
1577{
1578 m_borderHatchLines.clear();
1579}
1580
1581
1583{
1584 UnHatchBorder();
1585
1587 || m_borderHatchPitch == 0
1588 || m_Poly->IsEmpty() )
1589 {
1590 return;
1591 }
1592
1593 // set the "length" of hatch lines (the length on horizontal axis)
1594 int hatch_line_len = m_borderHatchPitch; // OK for DIAGONAL_EDGE style
1595
1596 // Calculate spacing between 2 hatch lines
1597 int spacing = m_borderHatchPitch; // OK for DIAGONAL_EDGE style
1598
1600 {
1601 // The spacing is twice the spacing for DIAGONAL_EDGE because one
1602 // full diagonal replaces 2 edge diagonal hatch segments in code
1603 spacing = m_borderHatchPitch * 2;
1604 hatch_line_len = -1; // Use full diagonal hatch line
1605 }
1606
1607 // To have a better look, give a slope depending on the layer
1608 int layer = GetFirstLayer();
1609 std::vector<double> slopes;
1610
1611 if( IsTeardropArea() )
1612 slopes = { 0.7, -0.7 };
1613 else if( layer & 1 )
1614 slopes = { 1 };
1615 else
1616 slopes = { -1 };
1617
1618 m_borderHatchLines = m_Poly->GenerateHatchLines( slopes, spacing, hatch_line_len );
1619}
1620
1621
1622std::vector<SEG> ZONE::GetHatchLines() const
1623{
1624 const FOOTPRINT* fp = GetParentFootprint();
1625
1626 if( !fp )
1627 return m_borderHatchLines;
1628
1629 const TRANSFORM_TRS& xform = fp->GetTransform();
1630 std::vector<SEG> result;
1631 result.reserve( m_borderHatchLines.size() );
1632
1633 for( const SEG& seg : m_borderHatchLines )
1634 result.emplace_back( xform.Apply( seg.A ), xform.Apply( seg.B ) );
1635
1636 return result;
1637}
1638
1639
1641{
1642 return pcbIUScale.mmToIU( ZONE_BORDER_HATCH_DIST_MM );
1643}
1644
1645
1647{
1648 return BITMAPS::add_zone;
1649}
1650
1651
1653{
1654 wxASSERT( aImage->Type() == PCB_ZONE_T );
1655
1656 std::swap( *static_cast<ZONE*>( this ), *static_cast<ZONE*>( aImage) );
1657}
1658
1659
1660std::vector<PCB_LAYER_ID> ZONE::GetFilledLayers() const
1661{
1662 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1663
1664 std::vector<PCB_LAYER_ID> layers;
1665
1666 layers.reserve( m_FilledPolysList.size() );
1667
1668 for( const auto& [ layer, poly ] : m_FilledPolysList )
1669 layers.push_back( layer );
1670
1671 return layers;
1672}
1673
1674
1676{
1677 m_Poly->CacheTriangulation();
1678}
1679
1680
1682{
1683 if( aLayer == UNDEFINED_LAYER )
1684 {
1685 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1686
1687 for( auto& [ layer, poly ] : m_FilledPolysList )
1688 poly->CacheTriangulation( false, aSubmitter );
1689
1690 m_Poly->CacheTriangulation();
1691 }
1692 else
1693 {
1694 // Grab a shared_ptr copy under the lock, then triangulate outside it.
1695 // Each layer's SHAPE_POLY_SET is independent, so concurrent triangulation
1696 // of different layers is safe once we have the shared_ptr.
1697 std::shared_ptr<SHAPE_POLY_SET> poly;
1698
1699 {
1700 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1701
1702 auto it = m_FilledPolysList.find( aLayer );
1703
1704 if( it != m_FilledPolysList.end() )
1705 poly = it->second;
1706 }
1707
1708 if( poly )
1709 poly->CacheTriangulation( false, aSubmitter );
1710 }
1711}
1712
1713
1714bool ZONE::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const
1715{
1716 if( GetNetCode() < 1 )
1717 return true;
1718
1719 if( !m_insulatedIslands.count( aLayer ) )
1720 return false;
1721
1722 return m_insulatedIslands.at( aLayer ).count( aPolyIdx );
1723}
1724
1725
1726void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aSameNetCollidingZones,
1727 std::vector<ZONE*>* aOtherNetIntersectingZones ) const
1728{
1729 int epsilon = pcbIUScale.mmToIU( 0.001 );
1730 BOX2I bbox = GetBoundingBox();
1731
1732 bbox.Inflate( epsilon );
1733
1734 for( ZONE* candidate : GetBoard()->Zones() )
1735 {
1736 if( candidate == this )
1737 continue;
1738
1739 if( !candidate->GetLayerSet().test( aLayer ) )
1740 continue;
1741
1742 if( candidate->GetIsRuleArea() || candidate->IsTeardropArea() )
1743 continue;
1744
1745 if( !candidate->GetBoundingBox().Intersects( bbox ) )
1746 continue;
1747
1748 if( candidate->GetNetCode() == GetNetCode() )
1749 {
1750 SHAPE_POLY_SET selfOutlineStorage;
1751 const SHAPE_POLY_SET* selfOutline = &selfOutlineStorage;
1752 SHAPE_POLY_SET candidateOutlineStorage;
1753 const SHAPE_POLY_SET* candidateOutline = &candidateOutlineStorage;
1754
1755 // GetBoardOutline() is expensive. Don't use it in Zone Filler unless we have to.
1756 if( GetParentFootprint() )
1757 selfOutlineStorage = GetBoardOutline();
1758 else
1759 selfOutline = Outline();
1760
1761 if( candidate->GetParentFootprint() )
1762 candidateOutlineStorage = candidate->GetBoardOutline();
1763 else
1764 candidateOutline = candidate->Outline();
1765
1766 if( selfOutline->Collide( candidateOutline ) )
1767 aSameNetCollidingZones->push_back( candidate );
1768 }
1769 else
1770 {
1771 aOtherNetIntersectingZones->push_back( candidate );
1772 }
1773 }
1774}
1775
1776
1777bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET* aBoardOutline,
1778 SHAPE_POLY_SET* aSmoothedPolyWithApron ) const
1779{
1780 if( GetNumCorners() <= 2 ) // malformed zone. polygon calculations will not like it ...
1781 return false;
1782
1783 // Processing of arc shapes in zones is not yet supported because Clipper can't do boolean
1784 // operations on them. The poly outline must be converted to segments first.
1785 SHAPE_POLY_SET flattened = GetBoardOutline();
1786 flattened.ClearArcs();
1787
1788 if( GetIsRuleArea() )
1789 {
1790 // We like keepouts just the way they are....
1791 aSmoothedPoly = std::move( flattened );
1792 return true;
1793 }
1794
1795 const BOARD* board = GetBoard();
1796 bool keepExternalFillets = false;
1797
1800
1801 if( IsTeardropArea() )
1802 {
1803 // We use teardrop shapes with no smoothing; these shapes are already optimized
1804 smooth_requested = false;
1805 }
1806
1807 if( board )
1808 keepExternalFillets = board->GetDesignSettings().m_ZoneKeepExternalFillets;
1809
1810 auto smooth =
1811 [&]( SHAPE_POLY_SET& aPoly )
1812 {
1813 if( !smooth_requested )
1814 return;
1815
1816 switch( m_cornerSmoothingType )
1817 {
1819 aPoly = aPoly.Chamfer( (int) m_cornerRadius );
1820 break;
1821
1823 aPoly = aPoly.Fillet( (int) m_cornerRadius, GetMaxError() );
1824 break;
1825
1826 default:
1827 break;
1828 }
1829 };
1830
1831 SHAPE_POLY_SET* maxExtents = &flattened;
1832 SHAPE_POLY_SET withFillets;
1833
1834 aSmoothedPoly = flattened;
1835
1836 // Should external fillets (that is, those applied to concave corners) be kept? While it
1837 // seems safer to never have copper extend outside the zone outline, 5.1.x and prior did
1838 // indeed fill them so we leave the mode available.
1839 if( keepExternalFillets && smooth_requested )
1840 {
1841 withFillets = flattened;
1842 smooth( withFillets );
1843 withFillets.BooleanAdd( flattened );
1844 maxExtents = &withFillets;
1845 }
1846
1847 // We now add in the areas of any same-net, intersecting zones. This keeps us from smoothing
1848 // corners at an intersection (which often produces undesired divots between the intersecting
1849 // zones -- see #2752).
1850 //
1851 // After smoothing, we'll subtract back out everything outside of our zone.
1852 std::vector<ZONE*> sameNetCollidingZones;
1853 std::vector<ZONE*> diffNetIntersectingZones;
1854 GetInteractingZones( aLayer, &sameNetCollidingZones, &diffNetIntersectingZones );
1855
1856 for( ZONE* sameNetZone : sameNetCollidingZones )
1857 {
1858 BOX2I sameNetBoundingBox = sameNetZone->GetBoundingBox();
1859
1860 // Note: a two-pass algorithm could use sameNetZone's actual fill instead of its outline.
1861 // This would obviate the need for the below wrinkles, in addition to fixing both issues
1862 // in #16095.
1863 // (And we wouldn't need to collect all the diffNetIntersectingZones either.)
1864
1865 SHAPE_POLY_SET sameNetPoly = sameNetZone->GetBoardOutline();
1866 sameNetPoly.ClearArcs();
1867
1868 SHAPE_POLY_SET diffNetPoly;
1869
1870 // Of course there's always a wrinkle. The same-net intersecting zone *might* get knocked
1871 // out along the border by a higher-priority, different-net zone. #12797
1872 for( ZONE* diffNetZone : diffNetIntersectingZones )
1873 {
1874 if( diffNetZone->HigherPriority( sameNetZone )
1875 && diffNetZone->GetBoundingBox().Intersects( sameNetBoundingBox ) )
1876 {
1877 SHAPE_POLY_SET diffNetOutline = diffNetZone->GetBoardOutline();
1878 diffNetOutline.ClearArcs();
1879
1880 diffNetPoly.BooleanAdd( diffNetOutline );
1881 }
1882 }
1883
1884 // Second wrinkle. After unioning the higher priority, different net zones together, we
1885 // need to check to see if they completely enclose our zone. If they do, then we need to
1886 // treat the enclosed zone as isolated, not connected to the outer zone. #13915
1887 bool isolated = false;
1888
1889 if( diffNetPoly.OutlineCount() )
1890 {
1891 SHAPE_POLY_SET thisPoly = GetBoardOutline();
1892 thisPoly.ClearArcs();
1893
1894 thisPoly.BooleanSubtract( diffNetPoly );
1895 isolated = thisPoly.OutlineCount() == 0;
1896 }
1897
1898 if( !isolated )
1899 aSmoothedPoly.BooleanAdd( sameNetPoly );
1900 }
1901
1902 if( aBoardOutline )
1903 {
1904 SHAPE_POLY_SET boardOutline = aBoardOutline->CloneDropTriangulation();
1905 boardOutline.ClearArcs();
1906
1907 aSmoothedPoly.BooleanIntersection( boardOutline );
1908 }
1909
1910 SHAPE_POLY_SET withSameNetIntersectingZones = aSmoothedPoly.CloneDropTriangulation();
1911
1912 smooth( aSmoothedPoly );
1913
1914 if( aSmoothedPolyWithApron )
1915 {
1916 // The same-net intersecting-zone code above makes sure the corner-smoothing algorithm
1917 // doesn't produce divots. But the min-thickness algorithm applied in fillCopperZone()
1918 // is *also* going to perform a deflate/inflate cycle, again leading to divots. So we
1919 // pre-inflate the contour by the min-thickness within the same-net-intersecting-zones
1920 // envelope.
1921 SHAPE_POLY_SET poly = maxExtents->CloneDropTriangulation();
1923
1924 if( !keepExternalFillets )
1925 poly.BooleanIntersection( withSameNetIntersectingZones );
1926
1927 *aSmoothedPolyWithApron = aSmoothedPoly;
1928 aSmoothedPolyWithApron->BooleanIntersection( poly );
1929 }
1930
1931 aSmoothedPoly.BooleanIntersection( *maxExtents );
1932
1933 return true;
1934}
1935
1936
1938{
1939 m_area = 0.0;
1940
1941 for( const auto& [layer, poly] : m_FilledPolysList )
1942 m_area += poly->Area();
1943
1944 return m_area;
1945}
1946
1947
1949{
1950 m_outlinearea = std::abs( m_Poly->Area() );
1951 return m_outlinearea;
1952}
1953
1954
1956 int aMaxError, ERROR_LOC aErrorLoc, SHAPE_POLY_SET* aBoardOutline ) const
1957{
1958 // Creates the zone outline polygon (with holes if any)
1959 SHAPE_POLY_SET polybuffer;
1960
1961 BuildSmoothedPoly( polybuffer, aLayer, aBoardOutline );
1962
1963 // Calculate the polygon with clearance
1964 // holes are linked to the main outline, so only one polygon is created.
1965 if( aClearance )
1966 {
1967 if( aErrorLoc == ERROR_OUTSIDE )
1968 aClearance += GetMaxError();
1969
1970 polybuffer.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, GetMaxError() );
1971 }
1972
1973 polybuffer.Fracture();
1974 aBuffer.Append( polybuffer );
1975}
1976
1977
1978std::shared_ptr<SHAPE> ZONE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING, DRC_CONSTRAINT_T ) const
1979{
1980 // Rule areas are never filled, so fall back to the outline. DRC relies on this to collide tracks,
1981 // vias and pads against keepout areas.
1982 if( GetIsRuleArea() )
1983 {
1984 // GetBoardOutline() is expensive. Don't use it in DRC if we don't have to.
1985 if( GetParentFootprint() )
1986 return std::make_shared<SHAPE_POLY_SET>( GetBoardOutline() );
1987 else
1988 return std::make_shared<SHAPE_POLY_SET>( *Outline() );
1989 }
1990
1991 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1992
1993 if( m_FilledPolysList.find( aLayer ) == m_FilledPolysList.end() )
1994 return std::make_shared<SHAPE_NULL>();
1995 else
1996 return m_FilledPolysList.at( aLayer );
1997}
1998
1999
2000double ZONE::GetCoverageArea( int aTextMargin ) const
2001{
2002 if( !GetIsRuleArea() )
2003 {
2004 // Unioning the layer fills stalls selection on a hatched plane. The largest layer is
2005 // exact for a single layer and bounds the union for the rest, which is enough to rank
2006 bool filled = false;
2007 double largest = 0.0;
2008
2009 for( PCB_LAYER_ID layer : GetLayerSet() )
2010 {
2011 if( !HasFilledPolysForLayer( layer ) )
2012 continue;
2013
2014 std::shared_ptr<SHAPE_POLY_SET> fill = GetFilledPolysList( layer );
2015
2016 if( fill->OutlineCount() == 0 )
2017 continue;
2018
2019 filled = true;
2020 largest = std::max( largest, fill->Area() );
2021 }
2022
2023 if( filled )
2024 return largest;
2025 }
2026
2027 // Rule areas are never filled, so TransformShapeToPolygon would report a zero coverage
2028 // area and make them appear as the smallest item under the cursor. That incorrectly
2029 // gives them selection precedence over the pads, tracks and footprints they enclose.
2030 // Use the outline area so an enclosed item is selected first while the rule area stays
2031 // available via its border and the disambiguation menu. An unfilled zone falls back the
2032 // same way so it does not collapse to a zero coverage area.
2033 SHAPE_POLY_SET outline = *m_Poly;
2034 return polygonArea( outline );
2035}
2036
2037
2038void ZONE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
2039 int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth ) const
2040{
2041 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for zones." ) );
2042
2043 std::shared_ptr<SHAPE_POLY_SET> fillPolys;
2044
2045 {
2046 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
2047
2048 if( !m_FilledPolysList.count( aLayer ) )
2049 return;
2050
2051 fillPolys = m_FilledPolysList.at( aLayer );
2052 }
2053
2054 if( !aClearance )
2055 {
2056 aBuffer.Append( *fillPolys );
2057 return;
2058 }
2059
2060 SHAPE_POLY_SET temp_buf = fillPolys->CloneDropTriangulation();
2061
2062 // Rebuild filled areas only if clearance is not 0
2063 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
2064 {
2065 if( aErrorLoc == ERROR_OUTSIDE )
2066 aClearance += aError;
2067
2068 temp_buf.InflateWithLinkedHoles( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aError );
2069 }
2070
2071 aBuffer.Append( temp_buf );
2072}
2073
2074
2076{
2077 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
2078
2079 if( m_FilledPolysList.count( aLayer ) && !m_FilledPolysList.at( aLayer )->IsEmpty() )
2080 aBuffer.Append( *m_FilledPolysList.at( aLayer ) );
2081}
2082
2083
2085{
2086 if( aLayerSet.count() == 0 )
2087 return;
2088
2089 std::scoped_lock lock( m_layerSetMutex, m_filledPolysListMutex );
2090
2091 if( m_layerSet != aLayerSet )
2092 {
2093 aLayerSet.RunOnLayers(
2094 [&]( PCB_LAYER_ID layer )
2095 {
2096 // Only keep layers that are present in the new set
2097 if( !aLayerSet.Contains( layer ) )
2098 {
2099 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
2100 m_filledPolysHash[layer] = {};
2101 m_insulatedIslands[layer] = {};
2102 }
2103 } );
2104 }
2105
2106 m_layerSet = aLayerSet;
2107}
2108
2109
2110bool ZONE::operator==( const BOARD_ITEM& aOther ) const
2111{
2112 if( aOther.Type() != Type() )
2113 return false;
2114
2115 const ZONE& other = static_cast<const ZONE&>( aOther );
2116 return *this == other;
2117}
2118
2119
2120bool ZONE::operator==( const ZONE& aOther ) const
2121
2122{
2123 if( aOther.Type() != Type() )
2124 return false;
2125
2126 const ZONE& other = static_cast<const ZONE&>( aOther );
2127
2128 if( GetIsRuleArea() != other.GetIsRuleArea() )
2129 return false;
2130
2131 if( GetIsRuleArea() )
2132 {
2134 return false;
2135
2136 if( GetDoNotAllowTracks() != other.GetDoNotAllowTracks() )
2137 return false;
2138
2139 if( GetDoNotAllowVias() != other.GetDoNotAllowVias() )
2140 return false;
2141
2143 return false;
2144
2145 if( GetDoNotAllowPads() != other.GetDoNotAllowPads() )
2146 return false;
2147
2149 return false;
2150
2152 return false;
2153
2155 return false;
2156 }
2157 else
2158 {
2159 if( GetAssignedPriority() != other.GetAssignedPriority() )
2160 return false;
2161
2162 if( GetMinThickness() != other.GetMinThickness() )
2163 return false;
2164
2166 return false;
2167
2168 if( GetCornerRadius() != other.GetCornerRadius() )
2169 return false;
2170
2171 if( GetTeardropParams() != other.GetTeardropParams() )
2172 return false;
2173 }
2174
2175 if( GetNumCorners() != other.GetNumCorners() )
2176 return false;
2177
2178 for( int ii = 0; ii < GetNumCorners(); ii++ )
2179 {
2180 if( GetCornerPosition( ii ) != other.GetCornerPosition( ii ) )
2181 return false;
2182 }
2183
2184 return true;
2185}
2186
2187
2188double ZONE::Similarity( const BOARD_ITEM& aOther ) const
2189{
2190 if( aOther.Type() != Type() )
2191 return 0.0;
2192
2193 const ZONE& other = static_cast<const ZONE&>( aOther );
2194
2195 if( GetIsRuleArea() != other.GetIsRuleArea() )
2196 return 0.0;
2197
2198 double similarity = 1.0;
2199
2200 if( GetLayerSet() != other.GetLayerSet() )
2201 similarity *= 0.9;
2202
2203 if( GetNetCode() != other.GetNetCode() )
2204 similarity *= 0.9;
2205
2206 if( !GetIsRuleArea() )
2207 {
2208 if( GetAssignedPriority() != other.GetAssignedPriority() )
2209 similarity *= 0.9;
2210
2211 if( GetMinThickness() != other.GetMinThickness() )
2212 similarity *= 0.9;
2213
2215 similarity *= 0.9;
2216
2217 if( GetCornerRadius() != other.GetCornerRadius() )
2218 similarity *= 0.9;
2219
2220 if( GetTeardropParams() != other.GetTeardropParams() )
2221 similarity *= 0.9;
2222 }
2223 else
2224 {
2226 similarity *= 0.9;
2227 if( GetDoNotAllowTracks() != other.GetDoNotAllowTracks() )
2228 similarity *= 0.9;
2229 if( GetDoNotAllowVias() != other.GetDoNotAllowVias() )
2230 similarity *= 0.9;
2232 similarity *= 0.9;
2233 if( GetDoNotAllowPads() != other.GetDoNotAllowPads() )
2234 similarity *= 0.9;
2235 }
2236
2237 std::vector<VECTOR2I> corners;
2238 std::vector<VECTOR2I> otherCorners;
2239 VECTOR2I lastCorner( 0, 0 );
2240
2241 for( int ii = 0; ii < GetNumCorners(); ii++ )
2242 {
2243 corners.push_back( lastCorner - GetCornerPosition( ii ) );
2244 lastCorner = GetCornerPosition( ii );
2245 }
2246
2247 lastCorner = VECTOR2I( 0, 0 );
2248 for( int ii = 0; ii < other.GetNumCorners(); ii++ )
2249 {
2250 otherCorners.push_back( lastCorner - other.GetCornerPosition( ii ) );
2251 lastCorner = other.GetCornerPosition( ii );
2252 }
2253
2254 size_t longest = alg::longest_common_subset( corners, otherCorners );
2255
2256 similarity *= std::pow( 0.9, GetNumCorners() + other.GetNumCorners() - 2 * longest );
2257
2258 return similarity;
2259}
2260
2261
2262static struct ZONE_DESC
2263{
2265 {
2267
2268 if( layerEnum.Choices().GetCount() == 0 )
2269 {
2270 layerEnum.Undefined( UNDEFINED_LAYER );
2271
2272 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
2273 layerEnum.Map( layer, LSET::Name( layer ) );
2274 }
2275
2277
2278 if( zcMap.Choices().GetCount() == 0 )
2279 {
2281 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
2282 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
2283 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
2284 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
2285 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
2286 }
2287
2289
2290 if( zfmMap.Choices().GetCount() == 0 )
2291 {
2293 zfmMap.Map( ZONE_FILL_MODE::POLYGONS, _HKI( "Solid fill" ) )
2294 .Map( ZONE_FILL_MODE::HATCH_PATTERN, _HKI( "Hatch pattern" ) )
2295 .Map( ZONE_FILL_MODE::COPPER_THIEVING, _HKI( "Copper thieving" ) );
2296 }
2297
2299
2300 if( tpMap.Choices().GetCount() == 0 )
2301 {
2303 tpMap.Map( THIEVING_PATTERN::DOTS, _HKI( "Dots" ) )
2304 .Map( THIEVING_PATTERN::SQUARES, _HKI( "Squares" ) )
2305 .Map( THIEVING_PATTERN::HATCH, _HKI( "Hatch" ) );
2306 }
2307
2309
2310 if( irmMap.Choices().GetCount() == 0 )
2311 {
2313 irmMap.Map( ISLAND_REMOVAL_MODE::ALWAYS, _HKI( "Always" ) )
2314 .Map( ISLAND_REMOVAL_MODE::NEVER, _HKI( "Never" ) )
2315 .Map( ISLAND_REMOVAL_MODE::AREA, _HKI( "Below area limit" ) );
2316 }
2317
2319
2320 if( rapstMap.Choices().GetCount() == 0 )
2321 {
2323 rapstMap.Map( PLACEMENT_SOURCE_T::SHEETNAME, _HKI( "Sheet Name" ) )
2324 .Map( PLACEMENT_SOURCE_T::COMPONENT_CLASS, _HKI( "Component Class" ) )
2326 .Map( PLACEMENT_SOURCE_T::DESIGN_BLOCK, _HKI( "Design Block" ) );
2327 }
2328
2332
2333 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
2334 new PROPERTY<ZONE, int>( _HKI( "Position X" ),
2335 NO_SETTER( ZONE, int ), static_cast<int ( ZONE::* )() const>( &ZONE::GetX ),
2338
2339 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
2340 new PROPERTY<ZONE, int>( _HKI( "Position Y" ),
2341 NO_SETTER( ZONE, int ), static_cast<int ( ZONE::* )() const>( &ZONE::GetY ),
2344
2345 auto isCopperZone =
2346 []( INSPECTABLE* aItem ) -> bool
2347 {
2348 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2349 return !zone->GetIsRuleArea() && IsCopperLayer( zone->GetFirstLayer() );
2350
2351 return false;
2352 };
2353
2354 // Hide net-bearing and hatch/island properties for copper-thieving zones.
2355 // Same predicate gates both kinds of properties.
2356 auto isNonThievingCopperZone =
2357 []( INSPECTABLE* aItem ) -> bool
2358 {
2359 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2360 {
2361 return !zone->GetIsRuleArea() && IsCopperLayer( zone->GetFirstLayer() )
2362 && !zone->IsCopperThieving();
2363 }
2364
2365 return false;
2366 };
2367
2368 auto isRuleArea =
2369 []( INSPECTABLE* aItem ) -> bool
2370 {
2371 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2372 return zone->GetIsRuleArea();
2373
2374 return false;
2375 };
2376
2377 auto isHatchedFill =
2378 []( INSPECTABLE* aItem ) -> bool
2379 {
2380 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2381 return zone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN;
2382
2383 return false;
2384 };
2385
2386 auto isThievingFill =
2387 []( INSPECTABLE* aItem ) -> bool
2388 {
2389 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2390 return zone->IsCopperThieving();
2391
2392 return false;
2393 };
2394
2395 auto isThievingHatch =
2396 []( INSPECTABLE* aItem ) -> bool
2397 {
2398 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2399 return zone->IsCopperThieving() && zone->GetThievingPattern() == THIEVING_PATTERN::HATCH;
2400
2401 return false;
2402 };
2403
2404 auto isThievingNonHatch =
2405 []( INSPECTABLE* aItem ) -> bool
2406 {
2407 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2408 return zone->IsCopperThieving() && zone->GetThievingPattern() != THIEVING_PATTERN::HATCH;
2409
2410 return false;
2411 };
2412
2413 auto isAreaBasedIslandRemoval =
2414 []( INSPECTABLE* aItem ) -> bool
2415 {
2416 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2417 return zone->GetIslandRemovalMode() == ISLAND_REMOVAL_MODE::AREA;
2418
2419 return false;
2420 };
2421
2422 // Visible for thieving zones only; ordinary zones use a layer set, not a single layer.
2423 propMgr.ReplaceProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ),
2426 .SetAvailableFunc( isThievingFill );
2427
2429 isNonThievingCopperZone );
2430 propMgr.OverrideAvailability( TYPE_HASH( ZONE ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net Class" ),
2431 isNonThievingCopperZone );
2432
2433 propMgr.AddProperty( new PROPERTY<ZONE, unsigned>( _HKI( "Priority" ),
2435 .SetAvailableFunc( isCopperZone );
2436
2437 propMgr.AddProperty( new PROPERTY<ZONE, wxString>( _HKI( "Name" ),
2439
2440 const wxString groupKeepout = _HKI( "Keepout" );
2441
2442 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Tracks" ),
2444 groupKeepout )
2445 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2446
2447 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Vias" ),
2449 groupKeepout )
2450 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2451
2452 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Pads" ),
2454 groupKeepout )
2455 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2456
2457 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Zone Fills" ),
2459 groupKeepout )
2460 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2461
2462 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Footprints" ),
2464 groupKeepout )
2465 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2466
2467
2468 const wxString groupPlacement = _HKI( "Placement" );
2469
2470 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Enable" ),
2472 groupPlacement )
2473 .SetAvailableFunc( isRuleArea );
2474
2475 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, PLACEMENT_SOURCE_T>( _HKI( "Source Type" ),
2477 groupPlacement )
2478 .SetAvailableFunc( isRuleArea );
2479
2480 propMgr.AddProperty( new PROPERTY<ZONE, wxString>( _HKI( "Source Name" ),
2482 groupPlacement )
2483 .SetAvailableFunc( isRuleArea );
2484
2485
2486 const wxString groupFill = _HKI( "Fill Style" );
2487
2488 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ZONE_FILL_MODE>( _HKI( "Fill Mode" ),
2490 groupFill )
2491 .SetAvailableFunc( isCopperZone ).SetIsCopyable();
2492
2493 propMgr.AddProperty( new PROPERTY<ZONE, EDA_ANGLE>( _HKI( "Hatch Orientation" ),
2495 groupFill )
2496 .SetAvailableFunc( isNonThievingCopperZone )
2497 .SetWriteableFunc( isHatchedFill ).SetIsCopyable();
2498
2499 auto atLeastMinWidthValidator =
2500 []( const wxAny&& aValue, EDA_ITEM* aZone ) -> VALIDATOR_RESULT
2501 {
2502 int val = aValue.As<int>();
2503 ZONE* zone = dynamic_cast<ZONE*>( aZone );
2504 wxCHECK( zone, std::nullopt );
2505
2506 if( val < zone->GetMinThickness() )
2507 return std::make_unique<VALIDATION_ERROR_MSG>( _( "Cannot be less than zone minimum width" ) );
2508
2509 return std::nullopt;
2510 };
2511
2512 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Hatch Width" ),
2514 groupFill )
2515 .SetAvailableFunc( isNonThievingCopperZone )
2516 .SetWriteableFunc( isHatchedFill )
2517 .SetValidator( atLeastMinWidthValidator ).SetIsCopyable();
2518
2519 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Hatch Gap" ),
2521 groupFill )
2522 .SetAvailableFunc( isNonThievingCopperZone )
2523 .SetWriteableFunc( isHatchedFill )
2524 .SetValidator( atLeastMinWidthValidator ).SetIsCopyable();
2525
2526 propMgr.AddProperty( new PROPERTY<ZONE, double>( _HKI( "Hatch Minimum Hole Ratio" ),
2528 groupFill )
2529 .SetAvailableFunc( isNonThievingCopperZone )
2530 .SetWriteableFunc( isHatchedFill )
2532
2533 // TODO: Smoothing effort needs to change to enum (in dialog too)
2534 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Smoothing Effort" ),
2536 groupFill )
2537 .SetAvailableFunc( isNonThievingCopperZone )
2538 .SetWriteableFunc( isHatchedFill ).SetIsCopyable();
2539
2540 propMgr.AddProperty( new PROPERTY<ZONE, double>( _HKI( "Smoothing Amount" ),
2542 groupFill )
2543 .SetAvailableFunc( isNonThievingCopperZone )
2544 .SetWriteableFunc( isHatchedFill ).SetIsCopyable();
2545
2546 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, THIEVING_PATTERN>( _HKI( "Thieving Pattern" ),
2548 groupFill )
2549 .SetAvailableFunc( isThievingFill ).SetIsCopyable();
2550
2551 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thieving Element Size" ),
2554 groupFill )
2555 .SetAvailableFunc( isThievingFill )
2556 .SetWriteableFunc( isThievingNonHatch )
2558
2559 // Gap is meaningful for all three patterns: edge-to-edge spacing between
2560 // adjacent stamps for dots/squares, line-to-line edge spacing for hatch.
2561 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thieving Gap" ),
2563 groupFill )
2564 .SetAvailableFunc( isThievingFill )
2566
2567 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thieving Line Width" ),
2570 groupFill )
2571 .SetAvailableFunc( isThievingFill )
2572 .SetWriteableFunc( isThievingHatch )
2574
2575 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Thieving Stagger" ),
2577 groupFill )
2578 .SetAvailableFunc( isThievingFill ).SetIsCopyable();
2579
2580 propMgr.AddProperty( new PROPERTY<ZONE, EDA_ANGLE>( _HKI( "Thieving Orientation" ),
2583 groupFill )
2584 .SetAvailableFunc( isThievingFill ).SetIsCopyable();
2585
2586 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ISLAND_REMOVAL_MODE>( _HKI( "Remove Islands" ),
2588 groupFill )
2589 .SetAvailableFunc( isNonThievingCopperZone ).SetIsCopyable();
2590
2591 propMgr.AddProperty( new PROPERTY<ZONE, long long int>( _HKI( "Minimum Island Area" ),
2593 groupFill )
2594 .SetAvailableFunc( isNonThievingCopperZone )
2595 .SetWriteableFunc( isAreaBasedIslandRemoval ).SetIsCopyable();
2596
2597 const wxString groupElectrical = _HKI( "Electrical" );
2598
2599 constexpr int maxClearance = pcbIUScale.mmToIU( ZONE_CLEARANCE_MAX_VALUE_MM );
2600 constexpr int minMinWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
2601
2602 propMgr.AddProperty( new PROPERTY<ZONE, std::optional<int>>( _HKI( "Clearance" ),
2604 groupElectrical )
2605 .SetAvailableFunc( isCopperZone )
2607
2608 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Minimum Width" ),
2610 groupElectrical )
2611 .SetAvailableFunc( isCopperZone )
2613
2614 // Pad connections and thermal-relief controls require a net to act on.
2615 // Thieving zones are netless and explicitly use ZONE_CONNECTION::NONE,
2616 // so hide these for them while keeping them visible for solid + hatched zones.
2617
2618 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ZONE_CONNECTION>( _HKI( "Pad Connections" ),
2620 groupElectrical )
2621 .SetAvailableFunc( isNonThievingCopperZone );
2622
2623 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thermal Relief Gap" ),
2625 groupElectrical )
2626 .SetAvailableFunc( isNonThievingCopperZone )
2628
2629 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thermal Relief Spoke Width" ),
2631 groupElectrical )
2632 .SetAvailableFunc( isNonThievingCopperZone )
2633 .SetValidator( atLeastMinWidthValidator );
2634 }
2636
KICOMMON_API types::KiCadObjectType ToProtoEnum(KICAD_T aValue)
KICOMMON_API KICAD_T FromProtoEnum(types::KiCadObjectType aValue)
Definition api_enums.cpp:55
ERROR_LOC
When approximating an arc or circle, should the error be placed on the outside or inside of the curve...
@ ERROR_OUTSIDE
constexpr EDA_IU_SCALE pcbIUScale
Definition base_units.h:128
BITMAPS
A list of all bitmap identifiers.
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
BASE_SET & set(size_t pos)
Definition base_set.h:126
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
virtual NETCLASS * GetEffectiveNetClass() const
Return the NETCLASS for this item.
virtual bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
BOARD_CONNECTED_ITEM(BOARD_ITEM *aParent, KICAD_T idtype)
void PackNet(kiapi::board::types::Net *aProto) const
virtual void SetNet(NETINFO_ITEM *aNetInfo)
Set a NET_INFO object for the 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.
void UnpackNet(const kiapi::board::types::Net &aProto)
Assigns a net to this item from an API message.
TEARDROP_PARAMETERS & GetTeardropParams()
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:84
BOARD_ITEM(BOARD_ITEM *aParent, KICAD_T idtype, PCB_LAYER_ID aLayer=F_Cu)
Definition board_item.h:86
friend class BOARD
Definition board_item.h:593
void SetUuidDirect(const KIID &aUuid)
Raw UUID assignment.
int GetY() const
Definition board_item.h:139
virtual BOARD_ITEM * Duplicate(bool addToParentGroup, BOARD_COMMIT *aCommit=nullptr) const
Create a copy of this BOARD_ITEM.
static double polygonArea(SHAPE_POLY_SET &aPolySet)
Area of aPolySet with every contour closed first, holes subtracted.
int GetX() const
Definition board_item.h:133
bool IsLocked() const override
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
FOOTPRINT * GetParentFootprint() const
BOARD_ITEM & operator=(const BOARD_ITEM &aOther)
Definition board_item.h:103
BOARD_ITEM_CONTAINER * GetParent() const
Definition board_item.h:266
wxString GetLayerName() const
Return the name of the PCB layer on which the item resides.
int GetMaxError() const
static wxString GetStandardLayerName(PCB_LAYER_ID aLayerId)
Return an "English Standard" name of a PCB layer when given aLayerNumber.
Definition board.h:1120
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:1131
std::unordered_map< const ZONE *, BOX2I > m_ZoneBBoxCache
Definition board.h:1843
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1301
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition box2.h:553
constexpr BOX2< Vec > & Normalize()
Ensure that the height and width are positive.
Definition box2.h:143
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:165
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:308
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:98
const KIID m_Uuid
Definition eda_item.h:599
bool m_forceVisible
Definition eda_item.h:614
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:608
bool HasFlag(EDA_ITEM_FLAGS aFlag) const
Definition eda_item.h:168
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition property.h:789
static ENUM_MAP< T > & Instance()
Definition property.h:783
ENUM_MAP & Undefined(T aValue)
Definition property.h:796
wxPGChoices & Choices()
Definition property.h:834
const TRANSFORM_TRS & GetTransform() const
Definition footprint.h:452
Class that other classes need to inherit from, in order to be inspectable.
Definition inspectable.h:39
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition view_item.h:176
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition view_item.h:181
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
bool IsLayerVisibleCached(int aLayer) const
Definition view.h:441
Definition kiid.h:46
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:37
static const LSET & FrontMask()
Return a mask holding all technical layers and the external CU layer on front side.
Definition lset.cpp:718
LSEQ UIOrder() const
Return the copper, technical and user layers in the order shown in layer widget.
Definition lset.cpp:739
static const LSET & BackMask()
Return a mask holding all technical layers and the external CU layer on back side.
Definition lset.cpp:725
void RunOnLayers(const std::function< void(PCB_LAYER_ID)> &aFunction) const
Execute a function on each layer of the LSET.
Definition lset.h:275
static LSET AllCuMask(int aCuLayerCount)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition lset.cpp:595
static const LSET & AllLayersMask()
Definition lset.cpp:637
static wxString Name(PCB_LAYER_ID aLayerId)
Return the fixed name association with aLayerId.
Definition lset.cpp:184
bool Contains(PCB_LAYER_ID aLayer) const
See if the layer set contains a PCB layer.
Definition lset.h:63
Handle the data for a net.
Definition netinfo.h:50
Definition pad.h:61
int GetLocalThermalGapOverride(wxString *aSource) const
Definition pad.cpp:2196
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition property.h:263
PROPERTY_BASE & SetWriteableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Definition property.h:293
PROPERTY_BASE & SetValidator(PROPERTY_VALIDATOR_FN &&aValidator)
Definition property.h:368
PROPERTY_BASE & SetIsCopyable(bool aIsCopyable=true)
Definition property.h:359
PROPERTY_BASE & SetIsHiddenFromPropertiesManager(bool aHide=true)
Definition property.h:325
Provide class metadata.
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
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:38
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.
bool Intersects(const SEG &aSeg) const
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const override
Check if point aP lies inside a closed shape.
Represent a set of closed polygons.
void BooleanAdd(const SHAPE_POLY_SET &b)
Perform boolean polyset union.
ITERATOR IterateWithHoles(int aOutline)
void ClearArcs()
Removes all arc references from all the outlines and holes in the polyset.
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
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.
int FullPointCount() const
Return the number of points in the shape poly set.
void Inflate(int aAmount, CORNER_STRATEGY aCornerStrategy, int aMaxError, bool aSimplify=false)
Perform outline inflation/deflation.
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)
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
void BooleanIntersection(const SHAPE_POLY_SET &b)
Perform boolean polyset intersection.
SEGMENT_ITERATOR IterateSegments(int aFirst, int aLast, bool aIterateHoles=false)
Return an iterator object, for iterating between aFirst and aLast outline, with or without holes (def...
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 InflateWithLinkedHoles(int aFactor, CORNER_STRATEGY aCornerStrategy, int aMaxError)
Perform outline inflation/deflation, using round corners.
void Fracture(bool aSimplify=true)
Convert a set of polygons with holes to a single outline with "slits"/"fractures" connecting the oute...
SHAPE_POLY_SET CloneDropTriangulation() const
void BooleanSubtract(const SHAPE_POLY_SET &b)
Perform boolean polyset difference.
std::function< void(std::function< void()>)> TASK_SUBMITTER
Callback that submits a unit of work for asynchronous execution.
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.
VECTOR2I InverseApply(const VECTOR2I &aPoint) const
VECTOR2I Apply(const VECTOR2I &aPoint) const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
Handle zones parameters.
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Copy settings to a given zone.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void SetHatchThickness(int aThickness)
Definition zone.h:326
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, const SHAPE_POLY_SET::TASK_SUBMITTER &aSubmitter={})
Definition zone.cpp:1681
void SetNeedRefill(bool aNeedRefill)
Definition zone.h:310
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:940
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1484
int m_borderHatchPitch
Definition zone.h:1054
wxString m_placementAreaSource
Definition zone.h:973
bool m_isRuleArea
A zone outline can be a rule area.
Definition zone.h:966
void SetDoNotAllowPads(bool aEnable)
Definition zone.h:851
void SetLayerProperties(const std::map< PCB_LAYER_ID, ZONE_LAYER_PROPERTIES > &aOther)
Definition zone.cpp:707
ZONE & operator=(const ZONE &aOther)
Definition zone.cpp:101
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:832
PLACEMENT_SOURCE_T m_placementAreaSourceType
Definition zone.h:972
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:1062
void SetLocalClearance(std::optional< int > aClearance)
Definition zone.h:183
bool m_doNotAllowVias
Definition zone.h:987
bool UnFill()
Removes the zone filling.
Definition zone.cpp:528
bool GetDoNotAllowVias() const
Definition zone.h:843
bool AppendCorner(const 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:1464
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:2075
void SetCornerRadius(unsigned int aRadius)
Definition zone.cpp:878
ZONE_FILL_MODE m_fillMode
Definition zone.h:1018
THIEVING_SETTINGS m_thievingSettings
Definition zone.h:1031
bool m_doNotAllowFootprints
Definition zone.h:990
bool unFillLocked()
Internal implementation of UnFill() that assumes the caller already holds m_filledPolysListMutex.
Definition zone.cpp:536
void TransformSmoothedOutlineToPolygon(SHAPE_POLY_SET &aBuffer, PCB_LAYER_ID aLayer, 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:1955
int m_ZoneMinThickness
Definition zone.h:994
BOARD_ITEM * Duplicate(bool addToParentGroup, BOARD_COMMIT *aCommit=nullptr) const override
Create a copy of this BOARD_ITEM.
Definition zone.cpp:230
int GetThievingLineWidth() const
Definition zone.h:387
void AddPolygon(std::vector< VECTOR2I > &aPolygon)
Add a polygon to the zone outline.
Definition zone.cpp:1447
double m_hatchSmoothingValue
Definition zone.h:1026
void SetLocalFlags(int aFlags)
Definition zone.h:419
int m_thermalReliefSpokeWidth
Definition zone.h:1016
wxString GetPlacementAreaSource() const
Definition zone.h:837
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:1097
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:1401
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:1058
wxString m_zoneName
An optional unique name for this zone, used for identifying it in DRC checking.
Definition zone.h:948
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition zone.cpp:1582
std::map< PCB_LAYER_ID, std::shared_ptr< SHAPE_POLY_SET > > m_FilledPolysList
Definition zone.h:1044
std::shared_ptr< SHAPE_POLY_SET > GetFilledPolysList(PCB_LAYER_ID aLayer) const
Definition zone.h:699
bool GetDoNotAllowPads() const
Definition zone.h:845
const BOX2I GetBoundingBox() const override
Definition zone.cpp:787
void SetMinThickness(int aMinThickness)
Definition zone.h:316
void SetPlacementAreaSource(const wxString &aSource)
Definition zone.h:838
BOX2I computeBoundingBox() const
Compute the bbox from scratch. Shared so the cached value can't diverge from the live one.
Definition zone.cpp:778
void SetThievingOrientation(const EDA_ANGLE &aOrientation)
Definition zone.h:407
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition zone.cpp:733
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
Definition zone.h:839
double m_outlinearea
Definition zone.h:1061
std::mutex m_filledPolysListMutex
Definition zone.h:1043
void SetThievingPattern(THIEVING_PATTERN aPattern)
Definition zone.h:361
wxString GetFriendlyName() const override
Definition zone.cpp:1302
bool GetDoNotAllowTracks() const
Definition zone.h:844
int GetLocalFlags() const
Definition zone.h:418
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition zone.cpp:216
void SetHatchOrientation(const EDA_ANGLE &aStep)
Definition zone.h:332
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuildBorderHatch)
Set all hatch parameters for the zone.
Definition zone.cpp:1563
void SetThievingElementSize(int aSize)
Definition zone.h:370
void SetHatchSmoothingValue(double aValue)
Definition zone.h:338
void CacheOutlineTriangulation()
Triangulate the zone outline only.
Definition zone.cpp:1675
std::map< PCB_LAYER_ID, ZONE_LAYER_PROPERTIES > m_layerProperties
Definition zone.h:953
void OnFootprintTransformed() override
Hook for items inside a footprint to refresh after the FP transform changes (translate,...
Definition zone.cpp:833
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:950
void SetHatchSmoothingLevel(int aLevel)
Definition zone.h:335
bool m_doNotAllowTracks
Definition zone.h:988
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
Definition zone.h:251
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition zone.cpp:573
void SetPlacementAreaSourceType(PLACEMENT_SOURCE_T aType)
Definition zone.h:840
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:640
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition zone.h:854
LSET m_fillFlags
Definition zone.h:1048
SHAPE_POLY_SET * Outline()
Definition zone.h:421
bool m_doNotAllowPads
Definition zone.h:989
ZONE(BOARD_ITEM_CONTAINER *parent)
Definition zone.cpp:52
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition zone.cpp:247
bool SetNetCode(int aNetCode, bool aNoAssert) override
Override that clamps the netcode to 0 when this zone is in copper-thieving fill mode.
Definition zone.cpp:622
void Move(const VECTOR2I &offset) override
Move the outlines.
Definition zone.cpp:1257
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
Definition zone.cpp:1714
std::atomic< int > m_bboxCacheTimeStamp
Definition zone.h:1070
bool IsCopperThieving() const
Definition zone.h:349
BOX2I m_bboxCache
Lock-free bbox cache, valid while m_bboxCacheTimeStamp matches the board timestamp.
Definition zone.h:1069
SHAPE_POLY_SET * m_Poly
Outline of the zone.
Definition zone.h:943
TEARDROP_TYPE m_teardropType
A zone outline can be a teardrop zone with different rules for priority (always bigger priority than ...
Definition zone.h:980
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:1051
~ZONE()
Definition zone.cpp:118
long long int GetMinIslandArea() const
Definition zone.h:857
int m_hatchSmoothingLevel
Definition zone.h:1022
void SetThievingStagger(bool aStagger)
Definition zone.h:397
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:2188
LSET m_layerSet
Definition zone.h:951
void SetIsRuleArea(bool aEnable)
Definition zone.h:833
int m_ZoneClearance
Definition zone.h:993
void CopyFrom(const BOARD_ITEM *aOther) override
Definition zone.cpp:111
void SetThievingGap(int aGap)
Definition zone.h:379
void SetDoNotAllowTracks(bool aEnable)
Definition zone.h:850
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
Definition zone.h:746
bool m_placementAreaEnabled
Placement rule area data.
Definition zone.h:971
const wxString & GetZoneName() const
Definition zone.h:160
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:842
int GetMinThickness() const
Definition zone.h:315
virtual void swapData(BOARD_ITEM *aImage) override
Definition zone.cpp:1652
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:961
SHAPE_POLY_SET GetBoardOutline() const
Definition zone.cpp:916
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
Definition zone.cpp:1418
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Rotate the outlines.
Definition zone.cpp:1338
ZONE_SETTINGS::CORNER_SMOOTHING GetCornerSmoothingType() const
Definition zone.h:771
bool HigherPriority(const ZONE *aOther) const
Definition zone.cpp:508
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:1068
void SetIsFilled(bool isFilled)
Definition zone.h:307
std::mutex m_layerSetMutex
Definition zone.h:950
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition zone.cpp:646
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition zone.cpp:1646
int m_hatchGap
Definition zone.h:1020
ZONE_CONNECTION GetPadConnection() const
Definition zone.h:312
bool HasFilledPolysForLayer(PCB_LAYER_ID aLayer) const
Definition zone.h:690
int GetHatchThickness() const
Definition zone.h:325
double GetHatchHoleMinArea() const
Definition zone.h:340
void invalidateBoundingBoxCache() const
Definition zone.cpp:821
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:665
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:1127
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition zone.cpp:771
int m_hatchBorderAlgorithm
Definition zone.h:1028
bool GetPlacementAreaEnabled() const
Definition zone.h:834
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:849
bool IsTeardropArea() const
Definition zone.h:807
std::vector< SEG > m_borderHatchLines
Definition zone.h:1055
VECTOR2I GetPosition() const override
Definition zone.cpp:564
int GetThermalReliefSpokeWidth() const
Definition zone.h:259
void SetNet(NETINFO_ITEM *aNetInfo) override
Override that drops aNetInfo when this zone is in copper-thieving fill mode.
Definition zone.cpp:631
virtual void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition zone.cpp:1369
void BuildHashValue(PCB_LAYER_ID aLayer)
Build the hash value of m_FilledPolysList, and store it internally in m_filledPolysHash.
Definition zone.cpp:899
void SetThermalReliefGap(int aThermalReliefGap)
Definition zone.h:240
EDA_ANGLE GetHatchOrientation() const
Definition zone.h:331
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
Definition zone.cpp:1777
int m_fillVersion
Definition zone.h:995
std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, FLASHING aFlash=FLASHING::DEFAULT, DRC_CONSTRAINT_T aUsage=NULL_CONSTRAINT) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition zone.cpp:1978
const VECTOR2I & GetCornerPosition(int aCornerIndex) const
Definition zone.h:657
EDA_ORIENTATION m_hatchOrientation
Definition zone.h:1021
bool GetDoNotAllowFootprints() const
Definition zone.h:846
ZONE_FILL_MODE GetFillMode() const
Definition zone.h:238
double m_hatchHoleMinArea
Definition zone.h:1027
std::vector< PCB_LAYER_ID > GetFilledLayers() const
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
Definition zone.cpp:1660
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition zone.h:133
bool GetThievingStagger() const
Definition zone.h:396
void SetDoNotAllowFootprints(bool aEnable)
Definition zone.h:852
void SetBorderHatchPitch(int aPitch)
Definition zone.h:868
void SetThievingLineWidth(int aWidth)
Definition zone.h:388
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:1726
void SetLayerSetAndRemoveUnusedFills(const LSET &aLayerSet)
Set the zone to be on the aLayerSet layers and only remove the fill polygons from the unused layers,...
Definition zone.cpp:2084
int GetHatchGap() const
Definition zone.h:328
double CalculateOutlineArea()
Compute the area of the zone outline (not the filled area).
Definition zone.cpp:1948
int GetThievingGap() const
Definition zone.h:378
void SetHatchHoleMinArea(double aPct)
Definition zone.h:341
unsigned m_priority
Priority: when a zone outline is inside and other zone, if its priority is higher the other zone prio...
Definition zone.h:960
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition zone.cpp:370
bool IsConflicting() const
For rule areas which exclude footprints (and therefore participate in courtyard conflicts during move...
Definition zone.cpp:558
bool m_doNotAllowZoneFills
For keepout zones only: what is not allowed inside the keepout ( pads, tracks and vias )
Definition zone.h:986
ISLAND_REMOVAL_MODE m_islandRemovalMode
Definition zone.h:997
std::vector< SEG > GetHatchLines() const
Definition zone.cpp:1622
bool m_isFilled
True when a zone was filled, false after deleting the filled areas.
Definition zone.h:1006
double GetHatchSmoothingValue() const
Definition zone.h:337
std::atomic< bool > m_needRefill
False when a zone was refilled, true after changes in zone params.
Definition zone.h:1013
THIEVING_PATTERN GetThievingPattern() const
Definition zone.h:360
bool GetDoNotAllowZoneFills() const
Definition zone.h:842
void MoveEdge(const VECTOR2I &offset, int aEdge)
Move the outline Edge.
Definition zone.cpp:1315
int GetHatchSmoothingLevel() const
Definition zone.h:334
unsigned int GetCornerRadius() const
Definition zone.h:775
int m_thermalReliefGap
Definition zone.h:1015
int GetThievingElementSize() const
Definition zone.h:369
SHAPE_POLY_SET GetLibraryOutline() const
Definition zone.cpp:910
bool IsOnCopperLayer() const override
Definition zone.cpp:615
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
Definition zone.cpp:1937
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:848
int m_hatchThickness
Definition zone.h:1019
void OnFootprintRescaled(double aRatioX, double aRatioY, double aLinearFactor, const VECTOR2I &aAnchor, const EDA_ANGLE &aParentRotate) override
Apply a parent footprint scale to this item.
Definition zone.cpp:1355
ZONE_SETTINGS::CORNER_SMOOTHING m_cornerSmoothingType
Definition zone.h:944
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:2038
void SetAssignedPriority(unsigned aPriority)
Definition zone.h:117
double m_area
Definition zone.h:1060
unsigned int m_cornerRadius
Definition zone.h:945
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition zone.h:313
void SetZoneName(const wxString &aName)
Definition zone.h:161
bool operator==(const ZONE &aOther) const
Definition zone.cpp:2120
void UnHatchBorder()
Clear the zone's hatch.
Definition zone.cpp:1576
void SetIslandRemovalMode(ISLAND_REMOVAL_MODE aRemove)
Definition zone.h:855
EDA_ANGLE GetThievingOrientation() const
Definition zone.h:405
double GetCoverageArea(int aTextMargin) const override
Return the board area this item covers, used to rank candidates under the cursor so a click on a smal...
Definition zone.cpp:2000
void SetOutline(SHAPE_POLY_SET *aOutline)
Definition zone.h:424
PCB_LAYER_ID GetFirstLayer() const
Definition zone.cpp:595
void SetMinIslandArea(long long int aArea)
Definition zone.h:858
virtual std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
Definition zone.cpp:713
HASH_128 GetHashValue(PCB_LAYER_ID aLayer)
Definition zone.cpp:890
ZONE_CONNECTION m_PadConnection
Definition zone.h:992
void InitDataFromSrcInCopyCtor(const ZONE &aZone, PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
Copy aZone data to me.
Definition zone.cpp:124
int GetThermalReliefGap() const
Definition zone.h:248
void SetHatchGap(int aStep)
Definition zone.h:329
static int GetDefaultHatchPitch()
Definition zone.cpp:1640
void SetPlacementAreaEnabled(bool aEnabled)
Definition zone.h:835
unsigned GetAssignedPriority() const
Definition zone.h:122
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition zone.h:617
bool SameNet(const ZONE *aOther) const
Definition zone.cpp:522
ZONE_BORDER_DISPLAY_STYLE m_borderStyle
Definition zone.h:1053
long long int m_minIslandArea
When island removal mode is set to AREA, islands below this area will be removed.
Definition zone.h:1003
A type-safe container of any type.
Definition ki_any.h:92
@ ROUND_ALL_CORNERS
All angles are rounded.
DRC_CONSTRAINT_T
Definition drc_rule.h:49
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
@ DEGREES_T
Definition eda_angle.h:30
#define PCB_EDIT_FRAME_NAME
@ NONE
Definition eda_fill.h:42
#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.
std::string source
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition layer_id.cpp:179
FLASHING
Enum used during connectivity building to ensure we do not query connectivity while building the data...
Definition layer_ids.h:180
bool IsCopperLayer(int aLayerId)
Test whether a layer is a copper layer.
Definition layer_ids.h:703
@ LAYER_CONFLICTS_SHADOW
Shadow layer for items flagged conflicting.
Definition layer_ids.h:306
@ LAYER_FOOTPRINTS_FR
Show footprints on front.
Definition layer_ids.h:255
@ LAYER_ZONES
Control for copper zone opacity/visibility (color ignored).
Definition layer_ids.h:291
@ LAYER_ZONE_START
Virtual layers for stacking zones and tracks on a given copper layer.
Definition layer_ids.h:345
@ LAYER_FOOTPRINTS_BK
Show footprints on back.
Definition layer_ids.h:256
PCB_LAYER_ID
A quick note on layer IDs:
Definition layer_ids.h:56
@ B_Cu
Definition layer_ids.h:61
@ UNDEFINED_LAYER
Definition layer_ids.h:57
@ F_Cu
Definition layer_ids.h:60
FLIP_DIRECTION
Definition mirror.h:23
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:182
void PackLayerSet(google::protobuf::RepeatedField< int > &aOutput, const LSET &aLayerSet)
LSET UnpackLayerSet(const google::protobuf::RepeatedField< int > &aProtoLayerSet)
KICOMMON_API void PackPolySet(types::PolySet &aOutput, const SHAPE_POLY_SET &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackCustomProperties(google::protobuf::RepeatedPtrField< types::CustomProperty > *aOutput, const EDA_ITEM &aItem)
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput, const EDA_IU_SCALE &aScale)
KICOMMON_API void UnpackCustomProperties(const google::protobuf::RepeatedPtrField< types::CustomProperty > &aInput, EDA_ITEM &aItem)
KICOMMON_API SHAPE_POLY_SET UnpackPolySet(const types::PolySet &aInput, const EDA_IU_SCALE &aScale)
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
#define _HKI(x)
Definition page_info.cpp:40
#define TYPE_HASH(x)
Macro to generate unique identifier for a type.
Definition property.h:74
#define IMPLEMENT_ENUM_TO_WXANY(type)
Definition property.h:888
#define NO_SETTER(owner, type)
Macro to define read-only fields (no setter method available)
Definition property.h:895
@ PT_DEGREE
Angle expressed in degrees.
Definition property.h:66
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
Definition property.h:65
@ PT_AREA
Area expressed in distance units-squared (mm/inch)
Definition property.h:64
@ PT_SIZE
Size expressed in distance units (mm/inch)
Definition property.h:63
#define REGISTER_TYPE(x)
Helper macro to map type hashes to names.
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.
A storage class for 128-bit hash value.
Definition hash_128.h:32
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
ZONE_DESC()
Definition zone.cpp:2264
std::optional< VECTOR2I > hatching_offset
TEARDROP_TYPE
define the type of a teardrop: on a via or pad, or a track end
int clearance
const int accuracy
wxString result
Test unit parsing edge cases and error handling.
@ PCB_ZONE_T
class ZONE, a copper pour area
Definition typeinfo.h:100
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
static SHAPE_POLY_SET g_nullPoly
Definition zone.cpp:887
static struct ZONE_DESC _ZONE_DESC
THIEVING_PATTERN
Shape stamped onto the grid for a copper-thieving fill.
ISLAND_REMOVAL_MODE
Whether or not to remove isolated islands from a zone.
ZONE_FILL_MODE
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.
PLACEMENT_SOURCE_T
#define ZONE_CLEARANCE_MAX_VALUE_MM
Definition zones.h:33
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition zones.h:43
@ THERMAL
Use thermal relief for pads.
Definition zones.h:46
@ THT_THERMAL
Thermal relief only for THT pads.
Definition zones.h:48
@ NONE
Pads are not covered.
Definition zones.h:45
@ FULL
pads are covered by copper
Definition zones.h:47
#define ZONE_BORDER_HATCH_DIST_MM
Definition zones.h:34
#define ZONE_BORDER_HATCH_MINDIST_MM
Definition zones.h:35
#define ZONE_THICKNESS_MIN_VALUE_MM
Definition zones.h:31
#define ZONE_BORDER_HATCH_MAXDIST_MM
Definition zones.h:36