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.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(
340 m_thievingSettings.orientation.AsDegrees() );
341 }
342
343 for( const auto& [layer, shape] : m_FilledPolysList )
344 {
345 types::ZoneFilledPolygons* filledLayer = zone.add_filled_polygons();
346 filledLayer->set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
347 kiapi::common::PackPolySet( *filledLayer->mutable_shapes(), *shape );
348 }
349
350 for( const auto& [layer, properties] : m_layerProperties )
351 {
352 types::ZoneLayerProperties* layerProperties = zone.add_layer_properties();
353 layerProperties->set_layer( ToProtoEnum<PCB_LAYER_ID, types::BoardLayer>( layer ) );
354
355 if( properties.hatching_offset.has_value() )
356 {
357 PackVector2( *layerProperties->mutable_hatching_offset(),
358 properties.hatching_offset.value() );
359 }
360 }
361
362 zone.mutable_border()->set_style(
364 zone.mutable_border()->mutable_pitch()->set_value_nm( m_borderHatchPitch );
365
366 kiapi::common::PackCustomProperties( zone.mutable_custom_properties(), *this );
367 aContainer.PackFrom( zone );
368}
369
370
371bool ZONE::Deserialize( const google::protobuf::Any& aContainer )
372{
373 using namespace kiapi::board;
374 types::Zone zone;
376
377 if( !aContainer.UnpackTo( &zone ) )
378 return false;
379
380 SetUuidDirect( KIID( zone.id().value() ) );
381 SetLayerSet( UnpackLayerSet( zone.layers() ) );
382 SetAssignedPriority( zone.priority() );
383 SetZoneName( wxString::FromUTF8( zone.name() ) );
384 kiapi::common::UnpackCustomProperties( zone.custom_properties(), *this );
385
386 if( zone.type() == types::ZoneType::ZT_RULE_AREA )
387 m_isRuleArea = true;
388
389 if( !m_Poly )
391
392 *m_Poly = kiapi::common::UnpackPolySet( zone.outline() );
393
394 if( m_Poly->OutlineCount() == 0 )
395 return false;
396
397 if( m_isRuleArea )
398 {
399 const types::RuleAreaSettings& ra = zone.rule_area_settings();
400 m_doNotAllowZoneFills = ra.keepout_copper();
401 m_doNotAllowFootprints = ra.keepout_footprints();
402 m_doNotAllowPads = ra.keepout_pads();
403 m_doNotAllowTracks = ra.keepout_tracks();
404 m_doNotAllowVias = ra.keepout_vias();
405
406 m_placementAreaEnabled = ra.placement_enabled();
407 m_placementAreaSource = wxString::FromUTF8( ra.placement_source() );
408 m_placementAreaSourceType = FromProtoEnum<PLACEMENT_SOURCE_T>( ra.placement_source_type() );
409 }
410 else
411 {
412 const types::CopperZoneSettings& cu = zone.copper_settings();
413 m_PadConnection = FromProtoEnum<ZONE_CONNECTION>( cu.connection().zone_connection() );
414 m_thermalReliefSpokeWidth = cu.connection().thermal_spokes().width().value_nm();
415 m_thermalReliefGap = cu.connection().thermal_spokes().gap().value_nm();
416 m_ZoneClearance = cu.clearance().value_nm();
417 m_ZoneMinThickness = cu.min_thickness().value_nm();
419 m_minIslandArea = cu.min_island_area();
420 // Route through SetFillMode so the thieving single-layer / net-less invariants
421 // are enforced on protobuf imports — a direct m_fillMode assignment would leave
422 // the multi-layer set unpacked at line 355 in place for ZFM_COPPER_THIEVING.
423 SetFillMode( FromProtoEnum<ZONE_FILL_MODE>( cu.fill_mode() ) );
424
426
427 if( cu.has_corner_radius() )
428 SetCornerRadius( cu.corner_radius().value_nm() );
429 else
430 SetCornerRadius( 0 );
431
432 m_hatchThickness = cu.hatch_settings().thickness().value_nm();
433 m_hatchGap = cu.hatch_settings().gap().value_nm();
434 m_hatchOrientation = EDA_ANGLE( cu.hatch_settings().orientation().value_degrees(), DEGREES_T );
435 m_hatchSmoothingValue = cu.hatch_settings().hatch_smoothing_ratio();
436 m_hatchHoleMinArea = cu.hatch_settings().hatch_hole_min_area_ratio();
437
438 switch( cu.hatch_settings().border_mode() )
439 {
440 default:
441 case types::ZHFBM_USE_MIN_ZONE_THICKNESS: m_hatchBorderAlgorithm = 0; break;
442 case types::ZHFBM_USE_HATCH_THICKNESS: m_hatchBorderAlgorithm = 1; break;
443 }
444
445 UnpackNet( cu.net() );
446 m_teardropType = FromProtoEnum<TEARDROP_TYPE>( cu.teardrop().type() );
447
448 if( cu.has_thieving_settings() )
449 {
450 const types::ThievingFillSettings& thieving = cu.thieving_settings();
451 m_thievingSettings.pattern =
452 FromProtoEnum<THIEVING_PATTERN>( thieving.pattern() );
453
454 auto assignIfPositive = []( int aProtoValue, int& aTarget )
455 {
456 if( aProtoValue > 0 )
457 aTarget = aProtoValue;
458 };
459
460 assignIfPositive( thieving.element_size().value_nm(), m_thievingSettings.element_size );
461 assignIfPositive( thieving.gap().value_nm(), m_thievingSettings.gap );
462 assignIfPositive( thieving.line_width().value_nm(), m_thievingSettings.line_width );
463
464 m_thievingSettings.stagger = thieving.stagger();
465 m_thievingSettings.orientation =
466 EDA_ANGLE( thieving.orientation().value_degrees(), DEGREES_T );
467 }
468
469 for( const auto& properties : zone.layer_properties() )
470 {
471 PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( properties.layer() );
472
473 ZONE_LAYER_PROPERTIES layerProperties;
474
475 if( properties.has_hatching_offset() )
476 layerProperties.hatching_offset = UnpackVector2( properties.hatching_offset() );
477
478 m_layerProperties[layer] = layerProperties;
479 }
480 }
481
483 m_borderHatchPitch = zone.border().pitch().value_nm();
484
485 if( zone.filled() )
486 {
487 SetIsFilled( true );
488 SetNeedRefill( false );
489
490 for( const types::ZoneFilledPolygons& fillLayer : zone.filled_polygons() )
491 {
492 PCB_LAYER_ID layer = FromProtoEnum<PCB_LAYER_ID>( fillLayer.layer() );
493 SHAPE_POLY_SET shape = kiapi::common::UnpackPolySet( fillLayer.shapes() );
494 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>( shape );
495 }
496 }
497 else
498 {
499 UnFill();
500 }
501
502
503 HatchBorder();
504
505 return true;
506}
507
508
509bool ZONE::HigherPriority( const ZONE* aOther ) const
510{
511 // Teardrops are always higher priority than regular zones, so if one zone is a teardrop
512 // and the other is not, then return higher priority as the teardrop
514 return static_cast<int>( m_teardropType ) > static_cast<int>( aOther->m_teardropType );
515
516 if( m_priority != aOther->m_priority )
517 return m_priority > aOther->m_priority;
518
519 return m_Uuid > aOther->m_Uuid;
520}
521
522
523bool ZONE::SameNet( const ZONE* aOther ) const
524{
525 return GetNetCode() == aOther->GetNetCode();
526}
527
528
530{
531 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
532
533 return unFillLocked();
534}
535
536
538{
539 bool change = false;
540
541 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
542 {
543 change |= !pair.second->IsEmpty();
544 m_insulatedIslands[pair.first].clear();
545
546 // Replace the shared_ptr with a new empty object rather than clearing the existing one.
547 // This ensures that any CN_ZONE_LAYERs holding shared_ptr copies still have valid data
548 // (the old, now orphaned SHAPE_POLY_SET) while we get a fresh container.
549 pair.second = std::make_shared<SHAPE_POLY_SET>();
550 }
551
552 m_isFilled = false;
553 m_fillFlags.reset();
554
555 return change;
556}
557
558
560{
561 return HasFlag( COURTYARD_CONFLICT );
562}
563
564
566{
567 if( m_Poly->OutlineCount() == 0 || m_Poly->TotalVertices() == 0 )
568 return VECTOR2I( 0, 0 );
569
570 return GetCornerPosition( 0 );
571}
572
573
575{
576 std::lock_guard<std::mutex> lock( m_layerSetMutex );
577
578 if( m_layerSet.count() == 1 )
579 {
580 // GetFirstLayer would try to acquire the mutex again, so inline its logic here
581 if( m_layerSet.count() == 0 )
582 return UNDEFINED_LAYER;
583
584 const LSEQ uiLayers = m_layerSet.UIOrder();
585
586 if( uiLayers.size() )
587 return uiLayers[0];
588
589 return m_layerSet.Seq()[0];
590 }
591
592 return UNDEFINED_LAYER;
593}
594
595
597{
598 std::lock_guard<std::mutex> lock( m_layerSetMutex );
599
600 if( m_layerSet.count() == 0 )
601 return UNDEFINED_LAYER;
602
603 const LSEQ uiLayers = m_layerSet.UIOrder();
604
605 // This can't use m_layerSet.count() because it's possible to have a zone on
606 // a rescue layer that is not in the UI order.
607 if( uiLayers.size() )
608 return uiLayers[0];
609
610 // If it's not in the UI set at all, just return the first layer in the set.
611 // (we know the count > 0)
612 return m_layerSet.Seq()[0];
613}
614
615
617{
618 std::lock_guard<std::mutex> lock( m_layerSetMutex );
619 return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
620}
621
622
623bool ZONE::SetNetCode( int aNetCode, bool aNoAssert )
624{
625 if( IsCopperThieving() )
626 aNetCode = 0;
627
628 return BOARD_CONNECTED_ITEM::SetNetCode( aNetCode, aNoAssert );
629}
630
631
632void ZONE::SetNet( NETINFO_ITEM* aNetInfo )
633{
634 if( IsCopperThieving() )
635 aNetInfo = nullptr;
636
638}
639
640
642{
643 SetLayerSet( LSET( { aLayer } ) );
644}
645
646
648{
649 if( m_fillMode == aFillMode )
650 return;
651
652 SetNeedRefill( true );
653 m_fillMode = aFillMode;
654
655 // Thieving zones are net-less and single-layer; clamp on transition so a
656 // multi-layer netted POLYGONS zone converted via the property panel or a
657 // load-time SetLayerSet-then-SetFillMode sequence cannot keep stale state.
659 {
662 }
663}
664
665
666void ZONE::SetLayerSet( const LSET& aLayerSet )
667{
668 if( aLayerSet.count() == 0 )
669 return;
670
671 // Thieving zones are single-layer; clamp here so direct callers cannot violate
672 // the invariant. UIOrder().front() matches GetFirstLayer().
673 const LSET effectiveSet = ( IsCopperThieving() && aLayerSet.count() > 1 )
674 ? LSET( { aLayerSet.UIOrder().front() } )
675 : aLayerSet;
676
677 std::scoped_lock lock( m_layerSetMutex, m_filledPolysListMutex );
678
679 if( m_layerSet != effectiveSet )
680 {
681 SetNeedRefill( true );
682
683 unFillLocked();
684
685 m_FilledPolysList.clear();
686 m_filledPolysHash.clear();
687 m_insulatedIslands.clear();
688
689 effectiveSet.RunOnLayers(
690 [&]( PCB_LAYER_ID layer )
691 {
692 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
693 m_filledPolysHash[layer] = {};
694 m_insulatedIslands[layer] = {};
695 } );
696
697 std::erase_if( m_layerProperties,
698 [&]( const auto& item )
699 {
700 return !effectiveSet.Contains( item.first );
701 } );
702 }
703
704 m_layerSet = effectiveSet;
705}
706
707
708void ZONE::SetLayerProperties( const std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES>& aOther )
709{
710 m_layerProperties = aOther;
711}
712
713
714std::vector<int> ZONE::ViewGetLayers() const
715{
716 std::lock_guard<std::mutex> lock( m_layerSetMutex );
717
718 std::vector<int> layers;
719 layers.reserve( 2 * m_layerSet.count() + 1 );
720
721 m_layerSet.RunOnLayers(
722 [&]( PCB_LAYER_ID layer )
723 {
724 layers.push_back( layer );
725 layers.push_back( layer + static_cast<int>( LAYER_ZONE_START ) );
726 } );
727
728 layers.push_back( LAYER_CONFLICTS_SHADOW );
729
730 return layers;
731}
732
733
734double ZONE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
735{
736 if( !aView )
737 return LOD_SHOW;
738
739 if( !aView->IsLayerVisibleCached( LAYER_ZONES ) )
740 return LOD_HIDE;
741
742 if( FOOTPRINT* parentFP = GetParentFootprint() )
743 {
744 const LSET zl = GetLayerSet();
745 bool onFront = ( zl & LSET::FrontMask() ).any();
746 bool onBack = ( zl & LSET::BackMask() ).any();
747
748 if( !onFront && !onBack )
749 {
750 onFront = parentFP->GetLayer() == F_Cu;
751 onBack = parentFP->GetLayer() == B_Cu;
752 }
753
754 const bool frHidden = !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_FR );
755 const bool bkHidden = !aView->IsLayerVisibleCached( LAYER_FOOTPRINTS_BK );
756
757 if( onFront && !onBack && frHidden )
758 return LOD_HIDE;
759
760 if( onBack && !onFront && bkHidden )
761 return LOD_HIDE;
762
763 if( onFront && onBack && frHidden && bkHidden )
764 return LOD_HIDE;
765 }
766
767 // Other layers are shown without any conditions
768 return LOD_SHOW;
769}
770
771
772bool ZONE::IsOnLayer( PCB_LAYER_ID aLayer ) const
773{
774 std::lock_guard<std::mutex> lock( m_layerSetMutex );
775 return m_layerSet.test( aLayer );
776}
777
778
780{
781 if( GetParentFootprint() )
782 return GetBoardOutline().BBox();
783
784 return m_Poly->BBox();
785}
786
787
789{
790 if( const BOARD* board = GetBoard() )
791 {
792 // Lock-free fast path, valid while the board timestamp matches what we cached for.
793 // Skips the caches mutex that otherwise serializes every fill worker.
794 if( m_bboxCacheTimeStamp.load( std::memory_order_acquire ) == board->GetTimeStamp() )
795 return m_bboxCache;
796
797 std::unordered_map<const ZONE*, BOX2I>& cache = board->m_ZoneBBoxCache;
798
799 {
800 std::shared_lock<std::shared_mutex> readLock( board->m_CachesMutex );
801
802 auto cacheIter = cache.find( this );
803
804 if( cacheIter != cache.end() )
805 return cacheIter->second;
806 }
807
808 BOX2I bbox = computeBoundingBox();
809
810 {
811 std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
812 cache[ this ] = bbox;
813 }
814
815 return bbox;
816 }
817
818 return computeBoundingBox();
819}
820
821
823{
824 const BOARD* board = GetBoard();
825 BOX2I bbox = computeBoundingBox();
826
827 if( board )
828 {
829 // Board cache, for callers that read it directly.
830 {
831 std::unique_lock<std::shared_mutex> writeLock( board->m_CachesMutex );
832 board->m_ZoneBBoxCache[this] = bbox;
833 }
834
835 // Per-zone lock-free copy. Single-threaded per zone, so box-before-timestamp (release)
836 // suffices for the acquiring reader in GetBoundingBox().
837 m_bboxCache = bbox;
838 m_bboxCacheTimeStamp.store( board->GetTimeStamp(), std::memory_order_release );
839 }
840}
841
842
843int ZONE::GetThermalReliefGap( PAD* aPad, wxString* aSource ) const
844{
845 if( aPad->GetLocalThermalGapOverride() == 0 )
846 {
847 if( aSource )
848 *aSource = _( "zone" );
849
850 return m_thermalReliefGap;
851 }
852
853 return aPad->GetLocalThermalGapOverride( aSource );
854
855}
856
857
858void ZONE::SetCornerRadius( unsigned int aRadius )
859{
860 if( m_cornerRadius != aRadius )
861 SetNeedRefill( true );
862
863 m_cornerRadius = aRadius;
864}
865
866
868
869
871{
872 if( !m_filledPolysHash.count( aLayer ) )
873 return g_nullPoly.GetHash();
874 else
875 return m_filledPolysHash.at( aLayer );
876}
877
878
880{
881 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
882
883 if( !m_FilledPolysList.count( aLayer ) )
884 m_filledPolysHash[aLayer] = g_nullPoly.GetHash();
885 else
886 m_filledPolysHash[aLayer] = m_FilledPolysList.at( aLayer )->GetHash();
887}
888
889
894
895
897{
898 SHAPE_POLY_SET poly;
899
900 if( const FOOTPRINT* fp = GetParentFootprint() )
901 {
902 if( m_Poly )
903 poly = m_Poly->CloneDropTriangulation();
904
905 const TRANSFORM_TRS& xform = fp->GetTransform();
906
907 for( auto it = poly.IterateWithHoles(); it; it++ )
908 poly.SetVertex( it.GetIndex(), xform.Apply( *it ) );
909 }
910 else
911 {
912 if( m_Poly )
913 poly = m_Poly->CloneDropTriangulation();
914 }
915
916 return poly;
917}
918
919
920bool ZONE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
921{
922 // When looking for an "exact" hit aAccuracy will be 0 which works poorly for very thin
923 // lines. Give it a floor.
924 int accuracy = std::max( aAccuracy, pcbIUScale.mmToIU( 0.1 ) );
925
926 return HitTestForCorner( aPosition, accuracy * 2 ) || HitTestForEdge( aPosition, accuracy );
927}
928
929
930bool ZONE::HitTestForCorner( const VECTOR2I& refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
931{
932 VECTOR2I libPos = refPos;
933
934 if( const FOOTPRINT* fp = GetParentFootprint() )
935 libPos = fp->GetTransform().InverseApply( refPos );
936
937 return m_Poly->CollideVertex( libPos, aCornerHit, aAccuracy );
938}
939
940
941bool ZONE::HitTestForEdge( const VECTOR2I& refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX* aCornerHit ) const
942{
943 VECTOR2I libPos = refPos;
944
945 if( const FOOTPRINT* fp = GetParentFootprint() )
946 libPos = fp->GetTransform().InverseApply( refPos );
947
948 return m_Poly->CollideEdge( libPos, aCornerHit, aAccuracy );
949}
950
951
952bool ZONE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
953{
954 // Calculate bounding box for zone
955 BOX2I bbox = GetBoundingBox();
956 bbox.Normalize();
957
958 BOX2I arect = aRect;
959 arect.Normalize();
960 arect.Inflate( aAccuracy );
961
962 if( aContained )
963 {
964 return arect.Contains( bbox );
965 }
966 else
967 {
968 // Fast test: if aBox is outside the polygon bounding box, rectangles cannot intersect
969 if( !arect.Intersects( bbox ) )
970 return false;
971
972 SHAPE_POLY_SET boardOutline = GetBoardOutline();
973 int count = boardOutline.TotalVertices();
974
975 for( int ii = 0; ii < count; ii++ )
976 {
977 const VECTOR2I& vertex = boardOutline.CVertex( ii );
978 const VECTOR2I& vertexNext = boardOutline.CVertex( ( ii + 1 ) % count );
979
980 // Test if the point is within the rect
981 if( arect.Contains( vertex ) )
982 return true;
983
984 // Test if this edge intersects the rect
985 if( arect.Intersects( vertex, vertexNext ) )
986 return true;
987 }
988
989 return false;
990 }
991}
992
993
994bool ZONE::HitTest( const SHAPE_LINE_CHAIN& aPoly, bool aContained ) const
995{
997
998 if( aContained )
999 {
1000 auto outlineIntersectingSelection =
1001 [&]()
1002 {
1003 for( auto segment = outline.IterateSegments(); segment; segment++ )
1004 {
1005 if( aPoly.Intersects( *segment ) )
1006 return true;
1007 }
1008
1009 return false;
1010 };
1011
1012 // In the case of contained selection, all vertices of the zone outline must be inside
1013 // the selection polygon, so we can check only the first vertex.
1014 auto vertexInsideSelection =
1015 [&]()
1016 {
1017 return aPoly.PointInside( outline.CVertex( 0 ) );
1018 };
1019
1020 return vertexInsideSelection() && !outlineIntersectingSelection();
1021 }
1022 else
1023 {
1024 // Touching selection - check if any segment of the zone contours collides with the
1025 // selection shape.
1026 for( auto segment = outline.IterateSegmentsWithHoles(); segment; segment++ )
1027 {
1028 if( aPoly.PointInside( ( *segment ).A ) )
1029 return true;
1030
1031 if( aPoly.Intersects( *segment ) )
1032 return true;
1033
1034 // Note: aPoly.Collide() could be used instead of two test above, but it is 3x slower.
1035 }
1036
1037 return false;
1038 }
1039}
1040
1041
1042std::optional<int> ZONE::GetLocalClearance() const
1043{
1044 return m_isRuleArea ? 0 : m_ZoneClearance;
1045}
1046
1047
1048bool ZONE::HitTestFilledArea( PCB_LAYER_ID aLayer, const VECTOR2I& aRefPos, int aAccuracy ) const
1049{
1050 // Rule areas have no filled area, but it's generally nice to treat their interior as if it were
1051 // filled so that people don't have to select them by their outline (which is min-width)
1052 if( GetIsRuleArea() )
1053 {
1054 VECTOR2I libPos = aRefPos;
1055
1056 if( const FOOTPRINT* fp = GetParentFootprint() )
1057 libPos = fp->GetTransform().InverseApply( aRefPos );
1058
1059 return m_Poly->Contains( libPos, -1, aAccuracy );
1060 }
1061
1062 std::shared_ptr<SHAPE_POLY_SET> fillPolys;
1063
1064 {
1065 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1066
1067 if( !m_FilledPolysList.count( aLayer ) )
1068 return false;
1069
1070 fillPolys = m_FilledPolysList.at( aLayer );
1071 }
1072
1073 return fillPolys->Contains( aRefPos, -1, aAccuracy );
1074}
1075
1076
1077bool ZONE::HitTestCutout( const VECTOR2I& aRefPos, int* aOutlineIdx, int* aHoleIdx ) const
1078{
1079 VECTOR2I libPos = aRefPos;
1080
1081 if( const FOOTPRINT* fp = GetParentFootprint() )
1082 libPos = fp->GetTransform().InverseApply( aRefPos );
1083
1084 // Iterate over each outline polygon in the zone and then iterate over
1085 // each hole it has to see if the point is in it.
1086 for( int i = 0; i < m_Poly->OutlineCount(); i++ )
1087 {
1088 for( int j = 0; j < m_Poly->HoleCount( i ); j++ )
1089 {
1090 if( m_Poly->Hole( i, j ).PointInside( libPos ) )
1091 {
1092 if( aOutlineIdx )
1093 *aOutlineIdx = i;
1094
1095 if( aHoleIdx )
1096 *aHoleIdx = j;
1097
1098 return true;
1099 }
1100 }
1101 }
1102
1103 return false;
1104}
1105
1106
1107void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
1108{
1109 wxString msg = GetFriendlyName();
1110
1111 aList.emplace_back( _( "Type" ), msg );
1112
1113 if( GetIsRuleArea() )
1114 {
1115 msg.Empty();
1116
1117 if( GetDoNotAllowVias() )
1118 AccumulateDescription( msg, _( "No vias" ) );
1119
1120 if( GetDoNotAllowTracks() )
1121 AccumulateDescription( msg, _( "No tracks" ) );
1122
1123 if( GetDoNotAllowPads() )
1124 AccumulateDescription( msg, _( "No pads" ) );
1125
1127 AccumulateDescription( msg, _( "No zone fills" ) );
1128
1130 AccumulateDescription( msg, _( "No footprints" ) );
1131
1132 if( !msg.IsEmpty() )
1133 aList.emplace_back( _( "Restrictions" ), msg );
1134
1136 aList.emplace_back( _( "Placement source" ), UnescapeString( GetPlacementAreaSource() ) );
1137 }
1138 else if( IsOnCopperLayer() )
1139 {
1140 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1141 {
1142 aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
1143
1144 aList.emplace_back( _( "Resolved Netclass" ),
1145 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
1146 }
1147
1148 // Display priority level
1149 aList.emplace_back( _( "Priority" ), wxString::Format( wxT( "%d" ), GetAssignedPriority() ) );
1150 }
1151
1152 if( aFrame->GetName() == PCB_EDIT_FRAME_NAME )
1153 {
1154 if( IsLocked() )
1155 aList.emplace_back( _( "Status" ), _( "Locked" ) );
1156 }
1157
1158 LSEQ layers = m_layerSet.Seq();
1159 wxString layerDesc;
1160
1161 if( layers.size() == 1 )
1162 {
1163 layerDesc.Printf( _( "%s" ), GetBoard()->GetLayerName( layers[0] ) );
1164 }
1165 else if (layers.size() == 2 )
1166 {
1167 layerDesc.Printf( _( "%s and %s" ),
1168 GetBoard()->GetLayerName( layers[0] ),
1169 GetBoard()->GetLayerName( layers[1] ) );
1170 }
1171 else if (layers.size() == 3 )
1172 {
1173 layerDesc.Printf( _( "%s, %s and %s" ),
1174 GetBoard()->GetLayerName( layers[0] ),
1175 GetBoard()->GetLayerName( layers[1] ),
1176 GetBoard()->GetLayerName( layers[2] ) );
1177 }
1178 else if( layers.size() > 3 )
1179 {
1180 layerDesc.Printf( _( "%s, %s and %d more" ),
1181 GetBoard()->GetLayerName( layers[0] ),
1182 GetBoard()->GetLayerName( layers[1] ),
1183 static_cast<int>( layers.size() - 2 ) );
1184 }
1185
1186 aList.emplace_back( _( "Layer" ), layerDesc );
1187
1188 if( !m_zoneName.empty() )
1189 aList.emplace_back( _( "Name" ), m_zoneName );
1190
1191 if( !GetIsRuleArea() ) // Show fill mode only for not rule areas
1192 {
1193 switch( m_fillMode )
1194 {
1195 case ZONE_FILL_MODE::POLYGONS: msg = _( "Solid" ); break;
1196 case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break;
1197 default: msg = _( "Unknown" ); break;
1198 }
1199
1200 aList.emplace_back( _( "Fill Mode" ), msg );
1201
1202 aList.emplace_back( _( "Filled Area" ),
1204
1205 wxString source;
1206 int clearance = GetOwnClearance( UNDEFINED_LAYER, &source );
1207
1208 if( !source.IsEmpty() )
1209 {
1210 aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ), aFrame->MessageTextFromValue( clearance ) ),
1211 wxString::Format( _( "(from %s)" ), source ) );
1212 }
1213 }
1214
1215 int count = 0;
1216
1217 if( GetIsRuleArea() )
1218 {
1219 double outline_area = CalculateOutlineArea();
1220 aList.emplace_back( _( "Outline Area" ),
1221 aFrame->MessageTextFromValue( outline_area, true, EDA_DATA_TYPE::AREA ) );
1222
1223 // No need to determine board vs. library outline. They'll have the same number of points.
1224 const SHAPE_POLY_SET* area_outline = Outline();
1225 count = area_outline->FullPointCount();
1226 }
1227 else if( !m_FilledPolysList.empty() )
1228 {
1229 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& ii: m_FilledPolysList )
1230 count += ii.second->TotalVertices();
1231 }
1232
1233 aList.emplace_back( _( "Corner Count" ), wxString::Format( wxT( "%d" ), count ) );
1234}
1235
1236
1237void ZONE::Move( const VECTOR2I& offset )
1238{
1239 VECTOR2I outlineOffset = offset;
1240
1241 if( const FOOTPRINT* fp = GetParentFootprint() )
1242 {
1243 const TRANSFORM_TRS& xform = fp->GetTransform();
1244 outlineOffset = xform.InverseApply( offset ) - xform.InverseApply( VECTOR2I( 0, 0 ) );
1245 }
1246
1247 m_Poly->Move( outlineOffset );
1248
1249 // Translate existing hatch lines instead of regenerating them. HatchBorder() is expensive
1250 // (O(n*m) segment intersections + point-in-polygon tests) and the hatch pattern is
1251 // invariant under translation.
1252 for( SEG& seg : m_borderHatchLines )
1253 {
1254 seg.A += outlineOffset;
1255 seg.B += outlineOffset;
1256 }
1257
1258 /* move fills */
1259 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1260 pair.second->Move( offset );
1261
1262 /*
1263 * move boundingbox cache
1264 *
1265 * While the cache will get nuked at the conclusion of the operation, we use it for some
1266 * things (such as drawing the parent group) during the move.
1267 */
1268 if( GetBoard() )
1269 {
1270 auto it = GetBoard()->m_ZoneBBoxCache.find( this );
1271
1272 if( it != GetBoard()->m_ZoneBBoxCache.end() )
1273 it->second.Move( offset );
1274 }
1275
1276 // Move doesn't bump the board timestamp, so invalidate the lock-free copy rather than race
1277 // readers by mutating it. GetBoundingBox() falls back to the board cache (moved above).
1278 m_bboxCacheTimeStamp.store( -1, std::memory_order_release );
1279}
1280
1281
1283{
1284 if( GetIsRuleArea() )
1285 return _( "Rule Area" );
1286 else if( IsTeardropArea() )
1287 return _( "Teardrop Area" );
1288 else if( IsOnCopperLayer() )
1289 return _( "Copper Zone" );
1290 else
1291 return _( "Non-copper Zone" );
1292}
1293
1294
1295void ZONE::MoveEdge( const VECTOR2I& offset, int aEdge )
1296{
1297 int next_corner;
1298
1299 if( m_Poly->GetNeighbourIndexes( aEdge, nullptr, &next_corner ) )
1300 {
1301 VECTOR2I libOffset = offset;
1302
1303 if( const FOOTPRINT* fp = GetParentFootprint() )
1304 {
1305 const TRANSFORM_TRS& xform = fp->GetTransform();
1306 libOffset = xform.InverseApply( offset ) - xform.InverseApply( VECTOR2I( 0, 0 ) );
1307 }
1308
1309 m_Poly->SetVertex( aEdge, m_Poly->CVertex( aEdge ) + libOffset );
1310 m_Poly->SetVertex( next_corner, m_Poly->CVertex( next_corner ) + libOffset );
1311 HatchBorder();
1312
1313 SetNeedRefill( true );
1314 }
1315}
1316
1317
1318void ZONE::Rotate( const VECTOR2I& aCentre, const EDA_ANGLE& aAngle )
1319{
1320 VECTOR2I outlineCentre = aCentre;
1321
1322 if( const FOOTPRINT* fp = GetParentFootprint() )
1323 outlineCentre = fp->GetTransform().InverseApply( aCentre );
1324
1325 m_Poly->Rotate( aAngle, outlineCentre );
1326 HatchBorder();
1327
1328 /* rotate filled areas: */
1329 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1330 pair.second->Rotate( aAngle, aCentre );
1331}
1332
1333
1334void ZONE::OnFootprintRescaled( double aRatioX, double aRatioY, double /* aLinearFactor */,
1335 const VECTOR2I& /* aAnchor */, const EDA_ANGLE& /* aParentRotate */ )
1336{
1337 if( aRatioX == 1.0 && aRatioY == 1.0 )
1338 return;
1339
1340 // Zone outline auto-derives from lib storage through the parent transform.
1341 // Just invalidate the fill since geometry-on-screen has changed.
1342 SetNeedRefill( true );
1343 UnFill();
1344}
1345
1346
1347void ZONE::Flip( const VECTOR2I& aCentre, FLIP_DIRECTION aFlipDirection )
1348{
1349 Mirror( aCentre, aFlipDirection );
1350
1351 std::map<PCB_LAYER_ID, SHAPE_POLY_SET> fillsCopy;
1352
1353 for( auto& [oldLayer, shapePtr] : m_FilledPolysList )
1354 fillsCopy[oldLayer] = *shapePtr;
1355
1356 std::map<PCB_LAYER_ID, ZONE_LAYER_PROPERTIES> layerPropertiesCopy = m_layerProperties;
1357
1358 LSET flipped;
1359
1360 for( PCB_LAYER_ID layer : GetLayerSet() )
1361 flipped.set( GetBoard()->FlipLayer( layer ) );
1362
1363 SetLayerSet( flipped );
1364
1365 for( auto& [oldLayer, properties] : layerPropertiesCopy )
1366 {
1367 PCB_LAYER_ID newLayer = GetBoard()->FlipLayer( oldLayer );
1368 m_layerProperties[newLayer] = properties;
1369 }
1370
1371 for( auto& [oldLayer, shape] : fillsCopy )
1372 {
1373 PCB_LAYER_ID newLayer = GetBoard()->FlipLayer( oldLayer );
1374 SetFilledPolysList( newLayer, shape );
1375 }
1376}
1377
1378
1379void ZONE::Mirror( const VECTOR2I& aMirrorRef, FLIP_DIRECTION aFlipDirection )
1380{
1381 VECTOR2I outlineRef = aMirrorRef;
1382
1383 if( const FOOTPRINT* fp = GetParentFootprint() )
1384 outlineRef = fp->GetTransform().InverseApply( aMirrorRef );
1385
1386 m_Poly->Mirror( outlineRef, aFlipDirection );
1387
1388 HatchBorder();
1389
1390 for( std::pair<const PCB_LAYER_ID, std::shared_ptr<SHAPE_POLY_SET>>& pair : m_FilledPolysList )
1391 pair.second->Mirror( aMirrorRef, aFlipDirection );
1392}
1393
1394
1395void ZONE::RemoveCutout( int aOutlineIdx, int aHoleIdx )
1396{
1397 // Ensure the requested cutout is valid
1398 if( m_Poly->OutlineCount() < aOutlineIdx || m_Poly->HoleCount( aOutlineIdx ) < aHoleIdx )
1399 return;
1400
1401 SHAPE_POLY_SET cutPoly( m_Poly->Hole( aOutlineIdx, aHoleIdx ) );
1402
1403 // Add the cutout back to the zone
1404 m_Poly->BooleanAdd( cutPoly );
1405
1406 SetNeedRefill( true );
1407}
1408
1409
1410void ZONE::AddPolygon( const SHAPE_LINE_CHAIN& aPolygon )
1411{
1412 wxASSERT( aPolygon.IsClosed() );
1413
1414 // Add the outline as a new polygon in the polygon set
1415 if( m_Poly->OutlineCount() == 0 )
1416 m_Poly->AddOutline( aPolygon );
1417 else
1418 m_Poly->AddHole( aPolygon );
1419
1420 SetNeedRefill( true );
1421}
1422
1423
1424void ZONE::AddPolygon( std::vector<VECTOR2I>& aPolygon )
1425{
1426 if( aPolygon.empty() )
1427 return;
1428
1429 SHAPE_LINE_CHAIN outline;
1430
1431 // Create an outline and populate it with the points of aPolygon
1432 for( const VECTOR2I& pt : aPolygon )
1433 outline.Append( pt );
1434
1435 outline.SetClosed( true );
1436
1437 AddPolygon( outline );
1438}
1439
1440
1441bool ZONE::AppendCorner( const VECTOR2I& aPosition, int aHoleIdx, bool aAllowDuplication )
1442{
1443 // Ensure the main outline exists:
1444 if( m_Poly->OutlineCount() == 0 )
1445 m_Poly->NewOutline();
1446
1447 // If aHoleIdx >= 0, the corner musty be added to the hole, index aHoleIdx.
1448 // (remember: the index of the first hole is 0)
1449 // Return error if it does not exist.
1450 if( aHoleIdx >= m_Poly->HoleCount( 0 ) )
1451 return false;
1452
1453 m_Poly->Append( aPosition.x, aPosition.y, -1, aHoleIdx, aAllowDuplication );
1454
1455 SetNeedRefill( true );
1456
1457 return true;
1458}
1459
1460
1461wxString ZONE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
1462{
1463 LSEQ layers = m_layerSet.Seq();
1464 wxString layerDesc;
1465
1466 auto layerName =
1467 [this]( PCB_LAYER_ID aLayer ) -> wxString
1468 {
1469 if( const BOARD* board = GetBoard() )
1470 return board->GetLayerName( aLayer );
1471
1472 return BOARD::GetStandardLayerName( aLayer );
1473 };
1474
1475 if( layers.size() == 1 )
1476 {
1477 layerDesc.Printf( _( "on %s" ), layerName( layers[0] ) );
1478 }
1479 else if (layers.size() == 2 )
1480 {
1481 layerDesc.Printf( _( "on %s and %s" ),
1482 layerName( layers[0] ),
1483 layerName( layers[1] ) );
1484 }
1485 else if (layers.size() == 3 )
1486 {
1487 layerDesc.Printf( _( "on %s, %s and %s" ),
1488 layerName( layers[0] ),
1489 layerName( layers[1] ),
1490 layerName( layers[2] ) );
1491 }
1492 else if( layers.size() > 3 )
1493 {
1494 layerDesc.Printf( _( "on %s, %s and %zu more" ),
1495 layerName( layers[0] ),
1496 layerName( layers[1] ),
1497 layers.size() - 2 );
1498 }
1499
1500 if( GetIsRuleArea() )
1501 {
1502 if( GetZoneName().IsEmpty() )
1503 {
1504 return wxString::Format( _( "Rule Area %s" ), layerDesc );
1505 }
1506 else
1507 {
1508 return wxString::Format( _( "Rule area '%s' %s" ),
1509 GetZoneName(),
1510 layerDesc );
1511 }
1512 }
1513 else if( IsTeardropArea() )
1514 {
1515 return wxString::Format( _( "Teardrop %s %s" ),
1516 GetNetnameMsg(),
1517 layerDesc );
1518 }
1519 else
1520 {
1521 if( GetZoneName().IsEmpty() )
1522 {
1523 return wxString::Format( _( "Zone %s %s, priority %d" ),
1524 GetNetnameMsg(),
1525 layerDesc,
1527 }
1528 else
1529 {
1530 return wxString::Format( _( "Zone '%s' %s %s, priority %d" ),
1531 GetZoneName(),
1532 GetNetnameMsg(),
1533 layerDesc,
1535 }
1536 }
1537}
1538
1539
1540void ZONE::SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch,
1541 bool aRebuildBorderHatch )
1542{
1543 aBorderHatchPitch = std::max( aBorderHatchPitch, pcbIUScale.mmToIU( ZONE_BORDER_HATCH_MINDIST_MM ) );
1544 aBorderHatchPitch = std::min( aBorderHatchPitch, pcbIUScale.mmToIU( ZONE_BORDER_HATCH_MAXDIST_MM ) );
1545 SetBorderHatchPitch( aBorderHatchPitch );
1546 m_borderStyle = aBorderHatchStyle;
1547
1548 if( aRebuildBorderHatch )
1549 HatchBorder();
1550}
1551
1552
1554{
1555 m_borderHatchLines.clear();
1556}
1557
1558
1560{
1561 UnHatchBorder();
1562
1564 || m_borderHatchPitch == 0
1565 || m_Poly->IsEmpty() )
1566 {
1567 return;
1568 }
1569
1570 // set the "length" of hatch lines (the length on horizontal axis)
1571 int hatch_line_len = m_borderHatchPitch; // OK for DIAGONAL_EDGE style
1572
1573 // Calculate spacing between 2 hatch lines
1574 int spacing = m_borderHatchPitch; // OK for DIAGONAL_EDGE style
1575
1577 {
1578 // The spacing is twice the spacing for DIAGONAL_EDGE because one
1579 // full diagonal replaces 2 edge diagonal hatch segments in code
1580 spacing = m_borderHatchPitch * 2;
1581 hatch_line_len = -1; // Use full diagonal hatch line
1582 }
1583
1584 // To have a better look, give a slope depending on the layer
1585 int layer = GetFirstLayer();
1586 std::vector<double> slopes;
1587
1588 if( IsTeardropArea() )
1589 slopes = { 0.7, -0.7 };
1590 else if( layer & 1 )
1591 slopes = { 1 };
1592 else
1593 slopes = { -1 };
1594
1595 m_borderHatchLines = m_Poly->GenerateHatchLines( slopes, spacing, hatch_line_len );
1596}
1597
1598
1599std::vector<SEG> ZONE::GetHatchLines() const
1600{
1601 const FOOTPRINT* fp = GetParentFootprint();
1602
1603 if( !fp )
1604 return m_borderHatchLines;
1605
1606 const TRANSFORM_TRS& xform = fp->GetTransform();
1607 std::vector<SEG> result;
1608 result.reserve( m_borderHatchLines.size() );
1609
1610 for( const SEG& seg : m_borderHatchLines )
1611 result.emplace_back( xform.Apply( seg.A ), xform.Apply( seg.B ) );
1612
1613 return result;
1614}
1615
1616
1618{
1619 return pcbIUScale.mmToIU( ZONE_BORDER_HATCH_DIST_MM );
1620}
1621
1622
1624{
1625 return BITMAPS::add_zone;
1626}
1627
1628
1630{
1631 wxASSERT( aImage->Type() == PCB_ZONE_T );
1632
1633 std::swap( *static_cast<ZONE*>( this ), *static_cast<ZONE*>( aImage) );
1634}
1635
1636
1638{
1639 if( aLayer == UNDEFINED_LAYER )
1640 {
1641 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1642
1643 for( auto& [ layer, poly ] : m_FilledPolysList )
1644 poly->CacheTriangulation( false, aSubmitter );
1645
1646 m_Poly->CacheTriangulation();
1647 }
1648 else
1649 {
1650 // Grab a shared_ptr copy under the lock, then triangulate outside it.
1651 // Each layer's SHAPE_POLY_SET is independent, so concurrent triangulation
1652 // of different layers is safe once we have the shared_ptr.
1653 std::shared_ptr<SHAPE_POLY_SET> poly;
1654
1655 {
1656 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1657
1658 auto it = m_FilledPolysList.find( aLayer );
1659
1660 if( it != m_FilledPolysList.end() )
1661 poly = it->second;
1662 }
1663
1664 if( poly )
1665 poly->CacheTriangulation( false, aSubmitter );
1666 }
1667}
1668
1669
1670bool ZONE::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const
1671{
1672 if( GetNetCode() < 1 )
1673 return true;
1674
1675 if( !m_insulatedIslands.count( aLayer ) )
1676 return false;
1677
1678 return m_insulatedIslands.at( aLayer ).count( aPolyIdx );
1679}
1680
1681
1682void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aSameNetCollidingZones,
1683 std::vector<ZONE*>* aOtherNetIntersectingZones ) const
1684{
1685 int epsilon = pcbIUScale.mmToIU( 0.001 );
1686 BOX2I bbox = GetBoundingBox();
1687
1688 bbox.Inflate( epsilon );
1689
1690 for( ZONE* candidate : GetBoard()->Zones() )
1691 {
1692 if( candidate == this )
1693 continue;
1694
1695 if( !candidate->GetLayerSet().test( aLayer ) )
1696 continue;
1697
1698 if( candidate->GetIsRuleArea() || candidate->IsTeardropArea() )
1699 continue;
1700
1701 if( !candidate->GetBoundingBox().Intersects( bbox ) )
1702 continue;
1703
1704 if( candidate->GetNetCode() == GetNetCode() )
1705 {
1706 SHAPE_POLY_SET selfOutlineStorage;
1707 const SHAPE_POLY_SET* selfOutline = &selfOutlineStorage;
1708 SHAPE_POLY_SET candidateOutlineStorage;
1709 const SHAPE_POLY_SET* candidateOutline = &candidateOutlineStorage;
1710
1711 // GetBoardOutline() is expensive. Don't use it in Zone Filler unless we have to.
1712 if( GetParentFootprint() )
1713 selfOutlineStorage = GetBoardOutline();
1714 else
1715 selfOutline = Outline();
1716
1717 if( candidate->GetParentFootprint() )
1718 candidateOutlineStorage = candidate->GetBoardOutline();
1719 else
1720 candidateOutline = candidate->Outline();
1721
1722 if( selfOutline->Collide( candidateOutline ) )
1723 aSameNetCollidingZones->push_back( candidate );
1724 }
1725 else
1726 {
1727 aOtherNetIntersectingZones->push_back( candidate );
1728 }
1729 }
1730}
1731
1732
1733bool ZONE::BuildSmoothedPoly( SHAPE_POLY_SET& aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET* aBoardOutline,
1734 SHAPE_POLY_SET* aSmoothedPolyWithApron ) const
1735{
1736 if( GetNumCorners() <= 2 ) // malformed zone. polygon calculations will not like it ...
1737 return false;
1738
1739 // Processing of arc shapes in zones is not yet supported because Clipper can't do boolean
1740 // operations on them. The poly outline must be converted to segments first.
1741 SHAPE_POLY_SET flattened = GetBoardOutline();
1742 flattened.ClearArcs();
1743
1744 if( GetIsRuleArea() )
1745 {
1746 // We like keepouts just the way they are....
1747 aSmoothedPoly = std::move( flattened );
1748 return true;
1749 }
1750
1751 const BOARD* board = GetBoard();
1752 bool keepExternalFillets = false;
1753
1756
1757 if( IsTeardropArea() )
1758 {
1759 // We use teardrop shapes with no smoothing; these shapes are already optimized
1760 smooth_requested = false;
1761 }
1762
1763 if( board )
1764 keepExternalFillets = board->GetDesignSettings().m_ZoneKeepExternalFillets;
1765
1766 auto smooth =
1767 [&]( SHAPE_POLY_SET& aPoly )
1768 {
1769 if( !smooth_requested )
1770 return;
1771
1772 switch( m_cornerSmoothingType )
1773 {
1775 aPoly = aPoly.Chamfer( (int) m_cornerRadius );
1776 break;
1777
1779 aPoly = aPoly.Fillet( (int) m_cornerRadius, GetMaxError() );
1780 break;
1781
1782 default:
1783 break;
1784 }
1785 };
1786
1787 SHAPE_POLY_SET* maxExtents = &flattened;
1788 SHAPE_POLY_SET withFillets;
1789
1790 aSmoothedPoly = flattened;
1791
1792 // Should external fillets (that is, those applied to concave corners) be kept? While it
1793 // seems safer to never have copper extend outside the zone outline, 5.1.x and prior did
1794 // indeed fill them so we leave the mode available.
1795 if( keepExternalFillets && smooth_requested )
1796 {
1797 withFillets = flattened;
1798 smooth( withFillets );
1799 withFillets.BooleanAdd( flattened );
1800 maxExtents = &withFillets;
1801 }
1802
1803 // We now add in the areas of any same-net, intersecting zones. This keeps us from smoothing
1804 // corners at an intersection (which often produces undesired divots between the intersecting
1805 // zones -- see #2752).
1806 //
1807 // After smoothing, we'll subtract back out everything outside of our zone.
1808 std::vector<ZONE*> sameNetCollidingZones;
1809 std::vector<ZONE*> diffNetIntersectingZones;
1810 GetInteractingZones( aLayer, &sameNetCollidingZones, &diffNetIntersectingZones );
1811
1812 for( ZONE* sameNetZone : sameNetCollidingZones )
1813 {
1814 BOX2I sameNetBoundingBox = sameNetZone->GetBoundingBox();
1815
1816 // Note: a two-pass algorithm could use sameNetZone's actual fill instead of its outline.
1817 // This would obviate the need for the below wrinkles, in addition to fixing both issues
1818 // in #16095.
1819 // (And we wouldn't need to collect all the diffNetIntersectingZones either.)
1820
1821 SHAPE_POLY_SET sameNetPoly = sameNetZone->GetBoardOutline();
1822 sameNetPoly.ClearArcs();
1823
1824 SHAPE_POLY_SET diffNetPoly;
1825
1826 // Of course there's always a wrinkle. The same-net intersecting zone *might* get knocked
1827 // out along the border by a higher-priority, different-net zone. #12797
1828 for( ZONE* diffNetZone : diffNetIntersectingZones )
1829 {
1830 if( diffNetZone->HigherPriority( sameNetZone )
1831 && diffNetZone->GetBoundingBox().Intersects( sameNetBoundingBox ) )
1832 {
1833 SHAPE_POLY_SET diffNetOutline = diffNetZone->GetBoardOutline();
1834 diffNetOutline.ClearArcs();
1835
1836 diffNetPoly.BooleanAdd( diffNetOutline );
1837 }
1838 }
1839
1840 // Second wrinkle. After unioning the higher priority, different net zones together, we
1841 // need to check to see if they completely enclose our zone. If they do, then we need to
1842 // treat the enclosed zone as isolated, not connected to the outer zone. #13915
1843 bool isolated = false;
1844
1845 if( diffNetPoly.OutlineCount() )
1846 {
1847 SHAPE_POLY_SET thisPoly = GetBoardOutline();
1848 thisPoly.ClearArcs();
1849
1850 thisPoly.BooleanSubtract( diffNetPoly );
1851 isolated = thisPoly.OutlineCount() == 0;
1852 }
1853
1854 if( !isolated )
1855 aSmoothedPoly.BooleanAdd( sameNetPoly );
1856 }
1857
1858 if( aBoardOutline )
1859 {
1860 SHAPE_POLY_SET boardOutline = aBoardOutline->CloneDropTriangulation();
1861 boardOutline.ClearArcs();
1862
1863 aSmoothedPoly.BooleanIntersection( boardOutline );
1864 }
1865
1866 SHAPE_POLY_SET withSameNetIntersectingZones = aSmoothedPoly.CloneDropTriangulation();
1867
1868 smooth( aSmoothedPoly );
1869
1870 if( aSmoothedPolyWithApron )
1871 {
1872 // The same-net intersecting-zone code above makes sure the corner-smoothing algorithm
1873 // doesn't produce divots. But the min-thickness algorithm applied in fillCopperZone()
1874 // is *also* going to perform a deflate/inflate cycle, again leading to divots. So we
1875 // pre-inflate the contour by the min-thickness within the same-net-intersecting-zones
1876 // envelope.
1877 SHAPE_POLY_SET poly = maxExtents->CloneDropTriangulation();
1879
1880 if( !keepExternalFillets )
1881 poly.BooleanIntersection( withSameNetIntersectingZones );
1882
1883 *aSmoothedPolyWithApron = aSmoothedPoly;
1884 aSmoothedPolyWithApron->BooleanIntersection( poly );
1885 }
1886
1887 aSmoothedPoly.BooleanIntersection( *maxExtents );
1888
1889 return true;
1890}
1891
1892
1894{
1895 m_area = 0.0;
1896
1897 for( const auto& [layer, poly] : m_FilledPolysList )
1898 m_area += poly->Area();
1899
1900 return m_area;
1901}
1902
1903
1905{
1906 m_outlinearea = std::abs( m_Poly->Area() );
1907 return m_outlinearea;
1908}
1909
1910
1912 int aMaxError, ERROR_LOC aErrorLoc, SHAPE_POLY_SET* aBoardOutline ) const
1913{
1914 // Creates the zone outline polygon (with holes if any)
1915 SHAPE_POLY_SET polybuffer;
1916
1917 BuildSmoothedPoly( polybuffer, aLayer, aBoardOutline );
1918
1919 // Calculate the polygon with clearance
1920 // holes are linked to the main outline, so only one polygon is created.
1921 if( aClearance )
1922 {
1923 if( aErrorLoc == ERROR_OUTSIDE )
1924 aClearance += GetMaxError();
1925
1926 polybuffer.Inflate( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, GetMaxError() );
1927 }
1928
1929 polybuffer.Fracture();
1930 aBuffer.Append( polybuffer );
1931}
1932
1933
1934std::shared_ptr<SHAPE> ZONE::GetEffectiveShape( PCB_LAYER_ID aLayer, FLASHING, DRC_CONSTRAINT_T ) const
1935{
1936 // Rule areas are never filled, so fall back to the outline. DRC relies on this to collide tracks,
1937 // vias and pads against keepout areas.
1938 if( GetIsRuleArea() )
1939 {
1940 // GetBoardOutline() is expensive. Don't use it in DRC if we don't have to.
1941 if( GetParentFootprint() )
1942 return std::make_shared<SHAPE_POLY_SET>( GetBoardOutline() );
1943 else
1944 return std::make_shared<SHAPE_POLY_SET>( *Outline() );
1945 }
1946
1947 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1948
1949 if( m_FilledPolysList.find( aLayer ) == m_FilledPolysList.end() )
1950 return std::make_shared<SHAPE_NULL>();
1951 else
1952 return m_FilledPolysList.at( aLayer );
1953}
1954
1955
1956void ZONE::TransformShapeToPolygon( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer, int aClearance,
1957 int aError, ERROR_LOC aErrorLoc, bool aIgnoreLineWidth ) const
1958{
1959 wxASSERT_MSG( !aIgnoreLineWidth, wxT( "IgnoreLineWidth has no meaning for zones." ) );
1960
1961 std::shared_ptr<SHAPE_POLY_SET> fillPolys;
1962
1963 {
1964 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1965
1966 if( !m_FilledPolysList.count( aLayer ) )
1967 return;
1968
1969 fillPolys = m_FilledPolysList.at( aLayer );
1970 }
1971
1972 if( !aClearance )
1973 {
1974 aBuffer.Append( *fillPolys );
1975 return;
1976 }
1977
1978 SHAPE_POLY_SET temp_buf = fillPolys->CloneDropTriangulation();
1979
1980 // Rebuild filled areas only if clearance is not 0
1981 if( aClearance > 0 || aErrorLoc == ERROR_OUTSIDE )
1982 {
1983 if( aErrorLoc == ERROR_OUTSIDE )
1984 aClearance += aError;
1985
1986 temp_buf.InflateWithLinkedHoles( aClearance, CORNER_STRATEGY::ROUND_ALL_CORNERS, aError );
1987 }
1988
1989 aBuffer.Append( temp_buf );
1990}
1991
1992
1994{
1995 std::lock_guard<std::mutex> lock( m_filledPolysListMutex );
1996
1997 if( m_FilledPolysList.count( aLayer ) && !m_FilledPolysList.at( aLayer )->IsEmpty() )
1998 aBuffer.Append( *m_FilledPolysList.at( aLayer ) );
1999}
2000
2001
2003{
2004 if( aLayerSet.count() == 0 )
2005 return;
2006
2007 std::scoped_lock lock( m_layerSetMutex, m_filledPolysListMutex );
2008
2009 if( m_layerSet != aLayerSet )
2010 {
2011 aLayerSet.RunOnLayers(
2012 [&]( PCB_LAYER_ID layer )
2013 {
2014 // Only keep layers that are present in the new set
2015 if( !aLayerSet.Contains( layer ) )
2016 {
2017 m_FilledPolysList[layer] = std::make_shared<SHAPE_POLY_SET>();
2018 m_filledPolysHash[layer] = {};
2019 m_insulatedIslands[layer] = {};
2020 }
2021 } );
2022 }
2023
2024 m_layerSet = aLayerSet;
2025}
2026
2027
2028bool ZONE::operator==( const BOARD_ITEM& aOther ) const
2029{
2030 if( aOther.Type() != Type() )
2031 return false;
2032
2033 const ZONE& other = static_cast<const ZONE&>( aOther );
2034 return *this == other;
2035}
2036
2037
2038bool ZONE::operator==( const ZONE& aOther ) const
2039
2040{
2041 if( aOther.Type() != Type() )
2042 return false;
2043
2044 const ZONE& other = static_cast<const ZONE&>( aOther );
2045
2046 if( GetIsRuleArea() != other.GetIsRuleArea() )
2047 return false;
2048
2049 if( GetIsRuleArea() )
2050 {
2052 return false;
2053
2054 if( GetDoNotAllowTracks() != other.GetDoNotAllowTracks() )
2055 return false;
2056
2057 if( GetDoNotAllowVias() != other.GetDoNotAllowVias() )
2058 return false;
2059
2061 return false;
2062
2063 if( GetDoNotAllowPads() != other.GetDoNotAllowPads() )
2064 return false;
2065
2067 return false;
2068
2070 return false;
2071
2073 return false;
2074 }
2075 else
2076 {
2077 if( GetAssignedPriority() != other.GetAssignedPriority() )
2078 return false;
2079
2080 if( GetMinThickness() != other.GetMinThickness() )
2081 return false;
2082
2084 return false;
2085
2086 if( GetCornerRadius() != other.GetCornerRadius() )
2087 return false;
2088
2089 if( GetTeardropParams() != other.GetTeardropParams() )
2090 return false;
2091 }
2092
2093 if( GetNumCorners() != other.GetNumCorners() )
2094 return false;
2095
2096 for( int ii = 0; ii < GetNumCorners(); ii++ )
2097 {
2098 if( GetCornerPosition( ii ) != other.GetCornerPosition( ii ) )
2099 return false;
2100 }
2101
2102 return true;
2103}
2104
2105
2106double ZONE::Similarity( const BOARD_ITEM& aOther ) const
2107{
2108 if( aOther.Type() != Type() )
2109 return 0.0;
2110
2111 const ZONE& other = static_cast<const ZONE&>( aOther );
2112
2113 if( GetIsRuleArea() != other.GetIsRuleArea() )
2114 return 0.0;
2115
2116 double similarity = 1.0;
2117
2118 if( GetLayerSet() != other.GetLayerSet() )
2119 similarity *= 0.9;
2120
2121 if( GetNetCode() != other.GetNetCode() )
2122 similarity *= 0.9;
2123
2124 if( !GetIsRuleArea() )
2125 {
2126 if( GetAssignedPriority() != other.GetAssignedPriority() )
2127 similarity *= 0.9;
2128
2129 if( GetMinThickness() != other.GetMinThickness() )
2130 similarity *= 0.9;
2131
2133 similarity *= 0.9;
2134
2135 if( GetCornerRadius() != other.GetCornerRadius() )
2136 similarity *= 0.9;
2137
2138 if( GetTeardropParams() != other.GetTeardropParams() )
2139 similarity *= 0.9;
2140 }
2141 else
2142 {
2144 similarity *= 0.9;
2145 if( GetDoNotAllowTracks() != other.GetDoNotAllowTracks() )
2146 similarity *= 0.9;
2147 if( GetDoNotAllowVias() != other.GetDoNotAllowVias() )
2148 similarity *= 0.9;
2150 similarity *= 0.9;
2151 if( GetDoNotAllowPads() != other.GetDoNotAllowPads() )
2152 similarity *= 0.9;
2153 }
2154
2155 std::vector<VECTOR2I> corners;
2156 std::vector<VECTOR2I> otherCorners;
2157 VECTOR2I lastCorner( 0, 0 );
2158
2159 for( int ii = 0; ii < GetNumCorners(); ii++ )
2160 {
2161 corners.push_back( lastCorner - GetCornerPosition( ii ) );
2162 lastCorner = GetCornerPosition( ii );
2163 }
2164
2165 lastCorner = VECTOR2I( 0, 0 );
2166 for( int ii = 0; ii < other.GetNumCorners(); ii++ )
2167 {
2168 otherCorners.push_back( lastCorner - other.GetCornerPosition( ii ) );
2169 lastCorner = other.GetCornerPosition( ii );
2170 }
2171
2172 size_t longest = alg::longest_common_subset( corners, otherCorners );
2173
2174 similarity *= std::pow( 0.9, GetNumCorners() + other.GetNumCorners() - 2 * longest );
2175
2176 return similarity;
2177}
2178
2179
2180static struct ZONE_DESC
2181{
2183 {
2185
2186 if( layerEnum.Choices().GetCount() == 0 )
2187 {
2188 layerEnum.Undefined( UNDEFINED_LAYER );
2189
2190 for( PCB_LAYER_ID layer : LSET::AllLayersMask() )
2191 layerEnum.Map( layer, LSET::Name( layer ) );
2192 }
2193
2195
2196 if( zcMap.Choices().GetCount() == 0 )
2197 {
2199 zcMap.Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
2200 .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
2201 .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
2202 .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
2203 .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Thermal reliefs for PTH" ) );
2204 }
2205
2207
2208 if( zfmMap.Choices().GetCount() == 0 )
2209 {
2211 zfmMap.Map( ZONE_FILL_MODE::POLYGONS, _HKI( "Solid fill" ) )
2212 .Map( ZONE_FILL_MODE::HATCH_PATTERN, _HKI( "Hatch pattern" ) )
2213 .Map( ZONE_FILL_MODE::COPPER_THIEVING, _HKI( "Copper thieving" ) );
2214 }
2215
2217
2218 if( tpMap.Choices().GetCount() == 0 )
2219 {
2221 tpMap.Map( THIEVING_PATTERN::DOTS, _HKI( "Dots" ) )
2222 .Map( THIEVING_PATTERN::SQUARES, _HKI( "Squares" ) )
2223 .Map( THIEVING_PATTERN::HATCH, _HKI( "Hatch" ) );
2224 }
2225
2227
2228 if( irmMap.Choices().GetCount() == 0 )
2229 {
2231 irmMap.Map( ISLAND_REMOVAL_MODE::ALWAYS, _HKI( "Always" ) )
2232 .Map( ISLAND_REMOVAL_MODE::NEVER, _HKI( "Never" ) )
2233 .Map( ISLAND_REMOVAL_MODE::AREA, _HKI( "Below area limit" ) );
2234 }
2235
2237
2238 if( rapstMap.Choices().GetCount() == 0 )
2239 {
2241 rapstMap.Map( PLACEMENT_SOURCE_T::SHEETNAME, _HKI( "Sheet Name" ) )
2242 .Map( PLACEMENT_SOURCE_T::COMPONENT_CLASS, _HKI( "Component Class" ) )
2244 }
2245
2249
2250 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position X" ),
2251 new PROPERTY<ZONE, int>( _HKI( "Position X" ),
2252 NO_SETTER( ZONE, int ), static_cast<int ( ZONE::* )() const>( &ZONE::GetX ),
2255
2256 propMgr.ReplaceProperty( TYPE_HASH( BOARD_ITEM ), _HKI( "Position Y" ),
2257 new PROPERTY<ZONE, int>( _HKI( "Position Y" ),
2258 NO_SETTER( ZONE, int ), static_cast<int ( ZONE::* )() const>( &ZONE::GetY ),
2261
2262 auto isCopperZone =
2263 []( INSPECTABLE* aItem ) -> bool
2264 {
2265 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2266 return !zone->GetIsRuleArea() && IsCopperLayer( zone->GetFirstLayer() );
2267
2268 return false;
2269 };
2270
2271 // Hide net-bearing and hatch/island properties for copper-thieving zones.
2272 // Same predicate gates both kinds of properties.
2273 auto isNonThievingCopperZone =
2274 []( INSPECTABLE* aItem ) -> bool
2275 {
2276 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2277 {
2278 return !zone->GetIsRuleArea() && IsCopperLayer( zone->GetFirstLayer() )
2279 && !zone->IsCopperThieving();
2280 }
2281
2282 return false;
2283 };
2284
2285 auto isRuleArea =
2286 []( INSPECTABLE* aItem ) -> bool
2287 {
2288 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2289 return zone->GetIsRuleArea();
2290
2291 return false;
2292 };
2293
2294 auto isHatchedFill =
2295 []( INSPECTABLE* aItem ) -> bool
2296 {
2297 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2298 return zone->GetFillMode() == ZONE_FILL_MODE::HATCH_PATTERN;
2299
2300 return false;
2301 };
2302
2303 auto isThievingFill =
2304 []( INSPECTABLE* aItem ) -> bool
2305 {
2306 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2307 return zone->IsCopperThieving();
2308
2309 return false;
2310 };
2311
2312 auto isThievingHatch =
2313 []( INSPECTABLE* aItem ) -> bool
2314 {
2315 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2316 return zone->IsCopperThieving() && zone->GetThievingPattern() == THIEVING_PATTERN::HATCH;
2317
2318 return false;
2319 };
2320
2321 auto isThievingNonHatch =
2322 []( INSPECTABLE* aItem ) -> bool
2323 {
2324 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2325 return zone->IsCopperThieving() && zone->GetThievingPattern() != THIEVING_PATTERN::HATCH;
2326
2327 return false;
2328 };
2329
2330 auto isAreaBasedIslandRemoval =
2331 []( INSPECTABLE* aItem ) -> bool
2332 {
2333 if( ZONE* zone = dynamic_cast<ZONE*>( aItem ) )
2334 return zone->GetIslandRemovalMode() == ISLAND_REMOVAL_MODE::AREA;
2335
2336 return false;
2337 };
2338
2339 // Visible for thieving zones only; ordinary zones use a layer set, not a single layer.
2340 propMgr.ReplaceProperty( TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Layer" ),
2343 .SetAvailableFunc( isThievingFill );
2344
2346 isNonThievingCopperZone );
2347 propMgr.OverrideAvailability( TYPE_HASH( ZONE ), TYPE_HASH( BOARD_CONNECTED_ITEM ), _HKI( "Net Class" ),
2348 isNonThievingCopperZone );
2349
2350 propMgr.AddProperty( new PROPERTY<ZONE, unsigned>( _HKI( "Priority" ),
2352 .SetAvailableFunc( isCopperZone );
2353
2354 propMgr.AddProperty( new PROPERTY<ZONE, wxString>( _HKI( "Name" ),
2356
2357 const wxString groupKeepout = _HKI( "Keepout" );
2358
2359 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Tracks" ),
2361 groupKeepout )
2362 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2363
2364 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Vias" ),
2366 groupKeepout )
2367 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2368
2369 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Pads" ),
2371 groupKeepout )
2372 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2373
2374 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Zone Fills" ),
2376 groupKeepout )
2377 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2378
2379 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Keep Out Footprints" ),
2381 groupKeepout )
2382 .SetAvailableFunc( isRuleArea ).SetIsCopyable();
2383
2384
2385 const wxString groupPlacement = _HKI( "Placement" );
2386
2387 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Enable" ),
2389 groupPlacement )
2390 .SetAvailableFunc( isRuleArea );
2391
2392 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, PLACEMENT_SOURCE_T>( _HKI( "Source Type" ),
2394 groupPlacement )
2395 .SetAvailableFunc( isRuleArea );
2396
2397 propMgr.AddProperty( new PROPERTY<ZONE, wxString>( _HKI( "Source Name" ),
2399 groupPlacement )
2400 .SetAvailableFunc( isRuleArea );
2401
2402
2403 const wxString groupFill = _HKI( "Fill Style" );
2404
2405 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ZONE_FILL_MODE>( _HKI( "Fill Mode" ),
2407 groupFill )
2408 .SetAvailableFunc( isCopperZone ).SetIsCopyable();
2409
2410 propMgr.AddProperty( new PROPERTY<ZONE, EDA_ANGLE>( _HKI( "Hatch Orientation" ),
2412 groupFill )
2413 .SetAvailableFunc( isNonThievingCopperZone )
2414 .SetWriteableFunc( isHatchedFill ).SetIsCopyable();
2415
2416 auto atLeastMinWidthValidator =
2417 []( const wxAny&& aValue, EDA_ITEM* aZone ) -> VALIDATOR_RESULT
2418 {
2419 int val = aValue.As<int>();
2420 ZONE* zone = dynamic_cast<ZONE*>( aZone );
2421 wxCHECK( zone, std::nullopt );
2422
2423 if( val < zone->GetMinThickness() )
2424 return std::make_unique<VALIDATION_ERROR_MSG>( _( "Cannot be less than zone minimum width" ) );
2425
2426 return std::nullopt;
2427 };
2428
2429 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Hatch Width" ),
2431 groupFill )
2432 .SetAvailableFunc( isNonThievingCopperZone )
2433 .SetWriteableFunc( isHatchedFill )
2434 .SetValidator( atLeastMinWidthValidator ).SetIsCopyable();
2435
2436 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Hatch Gap" ),
2438 groupFill )
2439 .SetAvailableFunc( isNonThievingCopperZone )
2440 .SetWriteableFunc( isHatchedFill )
2441 .SetValidator( atLeastMinWidthValidator ).SetIsCopyable();
2442
2443 propMgr.AddProperty( new PROPERTY<ZONE, double>( _HKI( "Hatch Minimum Hole Ratio" ),
2445 groupFill )
2446 .SetAvailableFunc( isNonThievingCopperZone )
2447 .SetWriteableFunc( isHatchedFill )
2449
2450 // TODO: Smoothing effort needs to change to enum (in dialog too)
2451 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Smoothing Effort" ),
2453 groupFill )
2454 .SetAvailableFunc( isNonThievingCopperZone )
2455 .SetWriteableFunc( isHatchedFill ).SetIsCopyable();
2456
2457 propMgr.AddProperty( new PROPERTY<ZONE, double>( _HKI( "Smoothing Amount" ),
2459 groupFill )
2460 .SetAvailableFunc( isNonThievingCopperZone )
2461 .SetWriteableFunc( isHatchedFill ).SetIsCopyable();
2462
2463 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, THIEVING_PATTERN>( _HKI( "Thieving Pattern" ),
2465 groupFill )
2466 .SetAvailableFunc( isThievingFill ).SetIsCopyable();
2467
2468 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thieving Element Size" ),
2471 groupFill )
2472 .SetAvailableFunc( isThievingFill )
2473 .SetWriteableFunc( isThievingNonHatch )
2475
2476 // Gap is meaningful for all three patterns: edge-to-edge spacing between
2477 // adjacent stamps for dots/squares, line-to-line edge spacing for hatch.
2478 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thieving Gap" ),
2480 groupFill )
2481 .SetAvailableFunc( isThievingFill )
2483
2484 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thieving Line Width" ),
2487 groupFill )
2488 .SetAvailableFunc( isThievingFill )
2489 .SetWriteableFunc( isThievingHatch )
2491
2492 propMgr.AddProperty( new PROPERTY<ZONE, bool>( _HKI( "Thieving Stagger" ),
2494 groupFill )
2495 .SetAvailableFunc( isThievingFill ).SetIsCopyable();
2496
2497 propMgr.AddProperty( new PROPERTY<ZONE, EDA_ANGLE>( _HKI( "Thieving Orientation" ),
2500 groupFill )
2501 .SetAvailableFunc( isThievingFill ).SetIsCopyable();
2502
2503 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ISLAND_REMOVAL_MODE>( _HKI( "Remove Islands" ),
2505 groupFill )
2506 .SetAvailableFunc( isNonThievingCopperZone ).SetIsCopyable();
2507
2508 propMgr.AddProperty( new PROPERTY<ZONE, long long int>( _HKI( "Minimum Island Area" ),
2510 groupFill )
2511 .SetAvailableFunc( isNonThievingCopperZone )
2512 .SetWriteableFunc( isAreaBasedIslandRemoval ).SetIsCopyable();
2513
2514 const wxString groupElectrical = _HKI( "Electrical" );
2515
2516 constexpr int maxClearance = pcbIUScale.mmToIU( ZONE_CLEARANCE_MAX_VALUE_MM );
2517 constexpr int minMinWidth = pcbIUScale.mmToIU( ZONE_THICKNESS_MIN_VALUE_MM );
2518
2519 propMgr.AddProperty( new PROPERTY<ZONE, std::optional<int>>( _HKI( "Clearance" ),
2521 groupElectrical )
2522 .SetAvailableFunc( isCopperZone )
2524
2525 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Minimum Width" ),
2527 groupElectrical )
2528 .SetAvailableFunc( isCopperZone )
2530
2531 // Pad connections and thermal-relief controls require a net to act on.
2532 // Thieving zones are netless and explicitly use ZONE_CONNECTION::NONE,
2533 // so hide these for them while keeping them visible for solid + hatched zones.
2534
2535 propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ZONE_CONNECTION>( _HKI( "Pad Connections" ),
2537 groupElectrical )
2538 .SetAvailableFunc( isNonThievingCopperZone );
2539
2540 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thermal Relief Gap" ),
2542 groupElectrical )
2543 .SetAvailableFunc( isNonThievingCopperZone )
2545
2546 propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thermal Relief Spoke Width" ),
2548 groupElectrical )
2549 .SetAvailableFunc( isNonThievingCopperZone )
2550 .SetValidator( atLeastMinWidthValidator );
2551 }
2553
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:121
BITMAPS
A list of all bitmap identifiers.
BOX2< VECTOR2I > BOX2I
Definition box2.h:927
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:578
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.
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:1112
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayer) const
Definition board.cpp:1124
std::unordered_map< const ZONE *, BOX2I > m_ZoneBBoxCache
Definition board.h:1834
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition board.cpp:1299
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:597
bool m_forceVisible
Definition eda_item.h:612
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition eda_item.h:606
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:776
static ENUM_MAP< T > & Instance()
Definition property.h:770
ENUM_MAP & Undefined(T aValue)
Definition property.h:783
wxPGChoices & Choices()
Definition property.h:821
const TRANSFORM_TRS & GetTransform() const
Definition footprint.h:451
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:439
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:263
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:2177
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.Helper macro to map type hashes to names.
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().
ZONE_SETTINGS handles zones parameters.
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
Handle a list of polygons defining a copper zone.
Definition zone.h:70
void SetHatchThickness(int aThickness)
Definition zone.h:326
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER, const SHAPE_POLY_SET::TASK_SUBMITTER &aSubmitter={})
Create a list of triangles that "fill" the solid areas used for instance to draw these solid areas on...
Definition zone.cpp:1637
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:920
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition zone.cpp:1461
int m_borderHatchPitch
Definition zone.h:1025
wxString m_placementAreaSource
Definition zone.h:946
bool m_isRuleArea
Definition zone.h:939
void SetDoNotAllowPads(bool aEnable)
Definition zone.h:826
void SetLayerProperties(const std::map< PCB_LAYER_ID, ZONE_LAYER_PROPERTIES > &aOther)
Definition zone.cpp:708
ZONE & operator=(const ZONE &aOther)
Definition zone.cpp:101
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition zone.h:807
PLACEMENT_SOURCE_T m_placementAreaSourceType
Definition zone.h:945
std::optional< int > GetLocalClearance() const override
Definition zone.cpp:1042
void SetLocalClearance(std::optional< int > aClearance)
Definition zone.h:183
bool m_doNotAllowVias
Definition zone.h:958
bool UnFill()
Removes the zone filling.
Definition zone.cpp:529
bool GetDoNotAllowVias() const
Definition zone.h:818
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:1441
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:1993
void SetCornerRadius(unsigned int aRadius)
Definition zone.cpp:858
ZONE_FILL_MODE m_fillMode
Definition zone.h:989
THIEVING_SETTINGS m_thievingSettings
Definition zone.h:1002
bool m_doNotAllowFootprints
Definition zone.h:961
bool unFillLocked()
Internal implementation of UnFill() that assumes the caller already holds m_filledPolysListMutex.
Definition zone.cpp:537
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:1911
int m_ZoneMinThickness
Definition zone.h:965
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:1424
double m_hatchSmoothingValue
Definition zone.h:997
void SetLocalFlags(int aFlags)
Definition zone.h:416
int m_thermalReliefSpokeWidth
Definition zone.h:987
wxString GetPlacementAreaSource() const
Definition zone.h:812
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:1077
EDA_ANGLE m_hatchOrientation
Definition zone.h:992
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:1379
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:1029
wxString m_zoneName
An optional unique name for this zone, used for identifying it in DRC checking.
Definition zone.h:923
void HatchBorder()
Compute the hatch lines depending on the hatch parameters and stores it in the zone's attribute m_bor...
Definition zone.cpp:1559
std::map< PCB_LAYER_ID, std::shared_ptr< SHAPE_POLY_SET > > m_FilledPolysList
Definition zone.h:1015
bool GetDoNotAllowPads() const
Definition zone.h:820
const BOX2I GetBoundingBox() const override
Definition zone.cpp:788
void SetMinThickness(int aMinThickness)
Definition zone.h:316
void SetPlacementAreaSource(const wxString &aSource)
Definition zone.h:813
BOX2I computeBoundingBox() const
Compute the bbox from scratch. Shared so the cached value can't diverge from the live one.
Definition zone.cpp:779
void SetThievingOrientation(const EDA_ANGLE &aOrientation)
Definition zone.h:406
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition zone.cpp:734
PLACEMENT_SOURCE_T GetPlacementAreaSourceType() const
Definition zone.h:814
double m_outlinearea
Definition zone.h:1032
std::mutex m_filledPolysListMutex
Definition zone.h:1014
void SetThievingPattern(THIEVING_PATTERN aPattern)
Definition zone.h:361
wxString GetFriendlyName() const override
Definition zone.cpp:1282
bool GetDoNotAllowTracks() const
Definition zone.h:819
int GetLocalFlags() const
Definition zone.h:415
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 SetThievingElementSize(int aSize)
Definition zone.h:370
void SetHatchSmoothingValue(double aValue)
Definition zone.h:338
std::map< PCB_LAYER_ID, ZONE_LAYER_PROPERTIES > m_layerProperties
Definition zone.h:928
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:930
void SetHatchSmoothingLevel(int aLevel)
Definition zone.h:335
bool m_doNotAllowTracks
Definition zone.h:959
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:574
void SetPlacementAreaSourceType(PLACEMENT_SOURCE_T aType)
Definition zone.h:815
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition zone.cpp:641
ISLAND_REMOVAL_MODE GetIslandRemovalMode() const
Definition zone.h:829
LSET m_fillFlags
Definition zone.h:1019
SHAPE_POLY_SET * Outline()
Definition zone.h:418
bool m_doNotAllowPads
Definition zone.h:960
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:623
void Move(const VECTOR2I &offset) override
Move the outlines.
Definition zone.cpp:1237
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Check if a given filled polygon is an insulated island.
Definition zone.cpp:1670
std::atomic< int > m_bboxCacheTimeStamp
Definition zone.h:1039
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:1038
SHAPE_POLY_SET * m_Poly
Outline of the zone.
Definition zone.h:918
TEARDROP_TYPE m_teardropType
Definition zone.h:952
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:1022
~ZONE()
Definition zone.cpp:118
long long int GetMinIslandArea() const
Definition zone.h:832
int m_hatchSmoothingLevel
Definition zone.h:993
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:2106
LSET m_layerSet
Definition zone.h:926
void SetIsRuleArea(bool aEnable)
Definition zone.h:808
int m_ZoneClearance
Definition zone.h:964
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:825
void SetFilledPolysList(PCB_LAYER_ID aLayer, const SHAPE_POLY_SET &aPolysList)
Set the list of filled polygons.
Definition zone.h:721
bool m_placementAreaEnabled
Placement rule area data.
Definition zone.h:944
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:822
int GetMinThickness() const
Definition zone.h:315
virtual void swapData(BOARD_ITEM *aImage) override
Definition zone.cpp:1629
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:941
SHAPE_POLY_SET GetBoardOutline() const
Definition zone.cpp:896
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
Definition zone.cpp:1395
void Rotate(const VECTOR2I &aCentre, const EDA_ANGLE &aAngle) override
Rotate the outlines.
Definition zone.cpp:1318
ZONE_SETTINGS::CORNER_SMOOTHING GetCornerSmoothingType() const
Definition zone.h:746
bool HigherPriority(const ZONE *aOther) const
Definition zone.cpp:509
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:1048
void SetIsFilled(bool isFilled)
Definition zone.h:307
std::mutex m_layerSetMutex
Definition zone.h:925
void SetFillMode(ZONE_FILL_MODE aFillMode)
Definition zone.cpp:647
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition zone.cpp:1623
int m_hatchGap
Definition zone.h:991
ZONE_CONNECTION GetPadConnection() const
Definition zone.h:312
int GetHatchThickness() const
Definition zone.h:325
double GetHatchHoleMinArea() const
Definition zone.h:340
void SetLayerSet(const LSET &aLayerSet) override
Definition zone.cpp:666
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:1107
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition zone.cpp:772
int m_hatchBorderAlgorithm
Definition zone.h:999
bool GetPlacementAreaEnabled() const
Definition zone.h:809
void SetDoNotAllowVias(bool aEnable)
Definition zone.h:824
bool IsTeardropArea() const
Definition zone.h:782
std::vector< SEG > m_borderHatchLines
Definition zone.h:1026
VECTOR2I GetPosition() const override
Definition zone.cpp:565
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:632
virtual void Flip(const VECTOR2I &aCentre, FLIP_DIRECTION aFlipDirection) override
Flip this object, i.e.
Definition zone.cpp:1347
void BuildHashValue(PCB_LAYER_ID aLayer)
Build the hash value of m_FilledPolysList, and store it internally in m_filledPolysHash.
Definition zone.cpp:879
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:1733
int m_fillVersion
Definition zone.h:966
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:1934
const VECTOR2I & GetCornerPosition(int aCornerIndex) const
Definition zone.h:650
bool GetDoNotAllowFootprints() const
Definition zone.h:821
ZONE_FILL_MODE GetFillMode() const
Definition zone.h:238
double m_hatchHoleMinArea
Definition zone.h:998
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:827
void SetBorderHatchPitch(int aPitch)
Definition zone.h:843
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:1682
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:2002
int GetHatchGap() const
Definition zone.h:328
double CalculateOutlineArea()
Compute the area of the zone outline (not the filled area).
Definition zone.cpp:1904
int GetThievingGap() const
Definition zone.h:378
void SetHatchHoleMinArea(double aPct)
Definition zone.h:341
unsigned m_priority
Definition zone.h:934
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition zone.cpp:371
bool IsConflicting() const
For rule areas which exclude footprints (and therefore participate in courtyard conflicts during move...
Definition zone.cpp:559
bool m_doNotAllowZoneFills
Definition zone.h:957
ISLAND_REMOVAL_MODE m_islandRemovalMode
Definition zone.h:968
std::vector< SEG > GetHatchLines() const
Definition zone.cpp:1599
bool m_isFilled
True when a zone was filled, false after deleting the filled areas.
Definition zone.h:977
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:984
THIEVING_PATTERN GetThievingPattern() const
Definition zone.h:360
bool GetDoNotAllowZoneFills() const
Definition zone.h:817
void MoveEdge(const VECTOR2I &offset, int aEdge)
Move the outline Edge.
Definition zone.cpp:1295
int GetHatchSmoothingLevel() const
Definition zone.h:334
unsigned int GetCornerRadius() const
Definition zone.h:750
int m_thermalReliefGap
Definition zone.h:986
int GetThievingElementSize() const
Definition zone.h:369
SHAPE_POLY_SET GetLibraryOutline() const
Definition zone.cpp:890
bool IsOnCopperLayer() const override
Definition zone.cpp:616
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
Definition zone.cpp:1893
void SetDoNotAllowZoneFills(bool aEnable)
Definition zone.h:823
int m_hatchThickness
Definition zone.h:990
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:1334
ZONE_SETTINGS::CORNER_SMOOTHING m_cornerSmoothingType
Definition zone.h:919
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:1956
void SetAssignedPriority(unsigned aPriority)
Definition zone.h:117
double m_area
Definition zone.h:1031
unsigned int m_cornerRadius
Definition zone.h:920
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:2038
void UnHatchBorder()
Clear the zone's hatch.
Definition zone.cpp:1553
void SetIslandRemovalMode(ISLAND_REMOVAL_MODE aRemove)
Definition zone.h:830
EDA_ANGLE GetThievingOrientation() const
Definition zone.h:405
void SetOutline(SHAPE_POLY_SET *aOutline)
Definition zone.h:421
PCB_LAYER_ID GetFirstLayer() const
Definition zone.cpp:596
void SetMinIslandArea(long long int aArea)
Definition zone.h:833
virtual std::vector< int > ViewGetLayers() const override
Return the all the layers within the VIEW the object is painted on.
Definition zone.cpp:714
HASH_128 GetHashValue(PCB_LAYER_ID aLayer)
Definition zone.cpp:870
ZONE_CONNECTION m_PadConnection
Definition zone.h:963
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:1617
void SetPlacementAreaEnabled(bool aEnabled)
Definition zone.h:810
unsigned GetAssignedPriority() const
Definition zone.h:122
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition zone.h:610
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aBorderHatchStyle, int aBorderHatchPitch, bool aRebuilBorderHatch)
Set all hatch parameters for the zone.
Definition zone.cpp:1540
bool SameNet(const ZONE *aOther) const
Definition zone.cpp:523
ZONE_BORDER_DISPLAY_STYLE m_borderStyle
Definition zone.h:1024
long long int m_minIslandArea
When island removal mode is set to AREA, islands below this area will be removed.
Definition zone.h:974
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:422
@ DEGREES_T
Definition eda_angle.h:31
#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.
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:411
#define _HKI(x)
Definition page_info.cpp:40
#define TYPE_HASH(x)
Definition property.h:74
#define IMPLEMENT_ENUM_TO_WXANY(type)
Definition property.h:875
#define NO_SETTER(owner, type)
Definition property.h:882
@ 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)
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:2182
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:683
static SHAPE_POLY_SET g_nullPoly
Definition zone.cpp:867
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