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