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