KiCad PCB EDA Suite
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 <dick@softplc.com>
6  * Copyright (C) 1992-2020 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 <bitmaps.h>
28 #include <geometry/shape_null.h>
29 #include <core/mirror.h>
30 #include <advanced_config.h>
31 #include <pcb_edit_frame.h>
32 #include <pcb_screen.h>
33 #include <board.h>
34 #include <zone.h>
35 #include <kicad_string.h>
36 #include <math_for_graphics.h>
39 #include <trigo.h>
40 #include <i18n_utility.h>
41 
42 ZONE::ZONE( BOARD_ITEM_CONTAINER* aParent, bool aInFP ) :
43  BOARD_CONNECTED_ITEM( aParent, aInFP ? PCB_FP_ZONE_T : PCB_ZONE_T ),
44  m_area( 0.0 )
45 {
46  m_CornerSelection = nullptr; // no corner is selected
47  m_isFilled = false; // fill status : true when the zone is filled
51  m_hv45 = false;
52  m_hatchThickness = 0;
53  m_hatchGap = 0;
54  m_hatchOrientation = 0.0;
55  m_hatchSmoothingLevel = 0; // Grid pattern smoothing type. 0 = no smoothing
56  m_hatchSmoothingValue = 0.1; // Grid pattern chamfer value relative to the gap value
57  // used only if m_hatchSmoothingLevel > 0
58  m_hatchHoleMinArea = 0.3; // Min size before holes are dropped (ratio of hole size)
59  m_hatchBorderAlgorithm = 1; // 0 = use zone min thickness; 1 = use hatch width
60  m_priority = 0;
62  SetIsRuleArea( aInFP ); // Zones living in footprints have the rule area option
63  SetDoNotAllowCopperPour( false ); // has meaning only if m_isRuleArea == true
64  SetDoNotAllowVias( true ); // has meaning only if m_isRuleArea == true
65  SetDoNotAllowTracks( true ); // has meaning only if m_isRuleArea == true
66  SetDoNotAllowPads( true ); // has meaning only if m_isRuleArea == true
67  SetDoNotAllowFootprints( false ); // has meaning only if m_isRuleArea == true
68  m_cornerRadius = 0;
69  SetLocalFlags( 0 ); // flags tempoarry used in zone calculations
70  m_Poly = new SHAPE_POLY_SET(); // Outlines
71  m_fillVersion = 5; // set the "old" way to build filled polygon areas (< 6.0.x)
73  aParent->GetZoneSettings().ExportSetting( *this );
74 
75  m_needRefill = false; // True only after some edition.
76 }
77 
78 
79 ZONE::ZONE( const ZONE& aZone )
80  : BOARD_CONNECTED_ITEM( aZone ),
81  m_Poly( nullptr ),
82  m_CornerSelection( nullptr )
83 {
85 }
86 
87 
88 ZONE& ZONE::operator=( const ZONE& aOther )
89 {
91 
92  InitDataFromSrcInCopyCtor( aOther );
93 
94  return *this;
95 }
96 
97 
99 {
100  delete m_Poly;
101  delete m_CornerSelection;
102 }
103 
104 
106 {
107  // members are expected non initialize in this.
108  // InitDataFromSrcInCopyCtor() is expected to be called
109  // only from a copy constructor.
110 
111  // Copy only useful EDA_ITEM flags:
112  m_flags = aZone.m_flags;
114 
115  // Replace the outlines for aZone outlines.
116  delete m_Poly;
117  m_Poly = new SHAPE_POLY_SET( *aZone.m_Poly );
118 
121  m_zoneName = aZone.m_zoneName;
122  m_priority = aZone.m_priority;
123  m_isRuleArea = aZone.m_isRuleArea;
124  SetLayerSet( aZone.GetLayerSet() );
125 
131 
133  m_ZoneClearance = aZone.m_ZoneClearance; // clearance value
138 
139  m_isFilled = aZone.m_isFilled;
140  m_needRefill = aZone.m_needRefill;
141 
144 
145  m_fillMode = aZone.m_fillMode; // solid vs. hatched
147  m_hatchGap = aZone.m_hatchGap;
153 
154  // For corner moving, corner index to drag, or nullptr if no selection
155  delete m_CornerSelection;
156  m_CornerSelection = nullptr;
157 
158  for( PCB_LAYER_ID layer : aZone.GetLayerSet().Seq() )
159  {
160  m_FilledPolysList[layer] = aZone.m_FilledPolysList.at( layer );
161  m_RawPolysList[layer] = aZone.m_RawPolysList.at( layer );
162  m_filledPolysHash[layer] = aZone.m_filledPolysHash.at( layer );
163  m_FillSegmList[layer] = aZone.m_FillSegmList.at( layer ); // vector <> copy
164  m_insulatedIslands[layer] = aZone.m_insulatedIslands.at( layer );
165  }
166 
170 
171  SetLocalFlags( aZone.GetLocalFlags() );
172 
173  m_netinfo = aZone.m_netinfo;
174 
175  m_hv45 = aZone.m_hv45;
176  m_area = aZone.m_area;
177 }
178 
179 
181 {
182  return new ZONE( *this );
183 }
184 
185 
187 {
188  bool change = false;
189 
190  for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
191  {
192  change |= !pair.second.IsEmpty();
193  pair.second.RemoveAllContours();
194  }
195 
196  for( std::pair<const PCB_LAYER_ID, ZONE_SEGMENT_FILL>& pair : m_FillSegmList )
197  {
198  change |= !pair.second.empty();
199  pair.second.clear();
200  }
201 
202  m_isFilled = false;
203  m_fillFlags.clear();
204 
205  return change;
206 }
207 
208 
209 wxPoint ZONE::GetPosition() const
210 {
211  return (wxPoint) GetCornerPosition( 0 );
212 }
213 
214 
216 {
217  return BOARD_ITEM::GetLayer();
218 }
219 
220 
222 {
223  return ( m_layerSet & LSET::AllCuMask() ).count() > 0;
224 }
225 
226 
227 bool ZONE::CommonLayerExists( const LSET aLayerSet ) const
228 {
229  LSET common = GetLayerSet() & aLayerSet;
230 
231  return common.count() > 0;
232 }
233 
234 
236 {
237  SetLayerSet( LSET( aLayer ) );
238 
239  m_layer = aLayer;
240 }
241 
242 
243 void ZONE::SetLayerSet( LSET aLayerSet )
244 {
245  if( GetIsRuleArea() )
246  {
247  // Rule areas can only exist on copper layers
248  aLayerSet &= LSET::AllCuMask();
249  }
250 
251  if( aLayerSet.count() == 0 )
252  return;
253 
254  if( m_layerSet != aLayerSet )
255  {
256  SetNeedRefill( true );
257 
258  UnFill();
259 
260  m_FillSegmList.clear();
261  m_FilledPolysList.clear();
262  m_RawPolysList.clear();
263  m_filledPolysHash.clear();
264  m_insulatedIslands.clear();
265 
266  for( PCB_LAYER_ID layer : aLayerSet.Seq() )
267  {
268  m_FillSegmList[layer] = {};
269  m_FilledPolysList[layer] = {};
270  m_RawPolysList[layer] = {};
271  m_filledPolysHash[layer] = {};
272  m_insulatedIslands[layer] = {};
273  }
274  }
275 
276  m_layerSet = aLayerSet;
277 
278  // Set the single layer parameter. For zones that can be on many layers, this parameter
279  // is arbitrary at best, but some code still uses it.
280  // Priority is F_Cu then B_Cu then to the first selected layer
281  m_layer = aLayerSet.Seq()[0];
282 
283  if( m_layer != F_Cu && aLayerSet[B_Cu] )
284  m_layer = B_Cu;
285 }
286 
287 
289 {
290  return m_layerSet;
291 }
292 
293 
294 void ZONE::ViewGetLayers( int aLayers[], int& aCount ) const
295 {
296  LSEQ layers = m_layerSet.Seq();
297 
298  for( unsigned int idx = 0; idx < layers.size(); idx++ )
299  aLayers[idx] = LAYER_ZONE_START + layers[idx];
300 
301  aCount = layers.size();
302 }
303 
304 
305 double ZONE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
306 {
307  constexpr double HIDE = std::numeric_limits<double>::max();
308 
309  return aView->IsLayerVisible( LAYER_ZONES ) ? 0.0 : HIDE;
310 }
311 
312 
313 bool ZONE::IsOnLayer( PCB_LAYER_ID aLayer ) const
314 {
315  return m_layerSet.test( aLayer );
316 }
317 
318 
320 {
321  auto bb = m_Poly->BBox();
322 
323  EDA_RECT ret( (wxPoint) bb.GetOrigin(), wxSize( bb.GetWidth(), bb.GetHeight() ) );
324 
325  return ret;
326 }
327 
328 
329 int ZONE::GetThermalReliefGap( PAD* aPad, wxString* aSource ) const
330 {
331  if( aPad->GetEffectiveThermalGap() == 0 )
332  {
333  if( aSource )
334  *aSource = _( "zone" );
335 
336  return m_thermalReliefGap;
337  }
338 
339  return aPad->GetEffectiveThermalGap( aSource );
340 
341 }
342 
343 
344 int ZONE::GetThermalReliefSpokeWidth( PAD* aPad, wxString* aSource ) const
345 {
346  if( aPad->GetEffectiveThermalSpokeWidth() == 0 )
347  {
348  if( aSource )
349  *aSource = _( "zone" );
350 
352  }
353 
354  return aPad->GetEffectiveThermalSpokeWidth( aSource );
355 }
356 
357 
358 void ZONE::SetCornerRadius( unsigned int aRadius )
359 {
360  if( m_cornerRadius != aRadius )
361  SetNeedRefill( true );
362 
363  m_cornerRadius = aRadius;
364 }
365 
366 
368 {
369  if( ADVANCED_CFG::GetCfg().m_DebugZoneFiller && LSET::InternalCuMask().Contains( aLayer ) )
370  return false;
371 
373 }
374 
375 
377 
378 
380 {
381  if( !m_filledPolysHash.count( aLayer ) )
382  return g_nullPoly.GetHash();
383  else
384  return m_filledPolysHash.at( aLayer );
385 }
386 
387 
389 {
390  if( !m_FilledPolysList.count( aLayer ) )
392  else
393  m_filledPolysHash[aLayer] = m_FilledPolysList.at( aLayer ).GetHash();
394 }
395 
396 
397 bool ZONE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
398 {
399  // Normally accuracy is zoom-relative, but for the generic HitTest we just use
400  // a fixed (small) value.
401  int accuracy = std::max( aAccuracy, Millimeter2iu( 0.1 ) );
402 
403  return HitTestForCorner( aPosition, accuracy * 2 ) || HitTestForEdge( aPosition, accuracy );
404 }
405 
406 
407 void ZONE::SetSelectedCorner( const wxPoint& aPosition, int aAccuracy )
408 {
410 
411  // If there is some corner to be selected, assign it to m_CornerSelection
412  if( HitTestForCorner( aPosition, aAccuracy * 2, corner )
413  || HitTestForEdge( aPosition, aAccuracy, corner ) )
414  {
415  if( m_CornerSelection == nullptr )
417 
418  *m_CornerSelection = corner;
419  }
420 }
421 
422 bool ZONE::HitTestForCorner( const wxPoint& refPos, int aAccuracy,
423  SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const
424 {
425  return m_Poly->CollideVertex( VECTOR2I( refPos ), aCornerHit, aAccuracy );
426 }
427 
428 
429 bool ZONE::HitTestForCorner( const wxPoint& refPos, int aAccuracy ) const
430 {
432  return HitTestForCorner( refPos, aAccuracy, dummy );
433 }
434 
435 
436 bool ZONE::HitTestForEdge( const wxPoint& refPos, int aAccuracy,
437  SHAPE_POLY_SET::VERTEX_INDEX& aCornerHit ) const
438 {
439  return m_Poly->CollideEdge( VECTOR2I( refPos ), aCornerHit, aAccuracy );
440 }
441 
442 
443 bool ZONE::HitTestForEdge( const wxPoint& refPos, int aAccuracy ) const
444 {
446  return HitTestForEdge( refPos, aAccuracy, dummy );
447 }
448 
449 
450 bool ZONE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
451 {
452  // Calculate bounding box for zone
453  EDA_RECT bbox = GetBoundingBox();
454  bbox.Normalize();
455 
456  EDA_RECT arect = aRect;
457  arect.Normalize();
458  arect.Inflate( aAccuracy );
459 
460  if( aContained )
461  {
462  return arect.Contains( bbox );
463  }
464  else
465  {
466  // Fast test: if aBox is outside the polygon bounding box, rectangles cannot intersect
467  if( !arect.Intersects( bbox ) )
468  return false;
469 
470  int count = m_Poly->TotalVertices();
471 
472  for( int ii = 0; ii < count; ii++ )
473  {
474  auto vertex = m_Poly->CVertex( ii );
475  auto vertexNext = m_Poly->CVertex( ( ii + 1 ) % count );
476 
477  // Test if the point is within the rect
478  if( arect.Contains( ( wxPoint ) vertex ) )
479  return true;
480 
481  // Test if this edge intersects the rect
482  if( arect.Intersects( ( wxPoint ) vertex, ( wxPoint ) vertexNext ) )
483  return true;
484  }
485 
486  return false;
487  }
488 }
489 
490 
491 int ZONE::GetLocalClearance( wxString* aSource ) const
492 {
493  if( m_isRuleArea )
494  return 0;
495 
496  if( aSource )
497  *aSource = _( "zone" );
498 
499  return m_ZoneClearance;
500 }
501 
502 
503 bool ZONE::HitTestFilledArea( PCB_LAYER_ID aLayer, const wxPoint &aRefPos, int aAccuracy ) const
504 {
505  // Rule areas have no filled area, but it's generally nice to treat their interior as if it were
506  // filled so that people don't have to select them by their outline (which is min-width)
507  if( GetIsRuleArea() )
508  return m_Poly->Contains( VECTOR2I( aRefPos.x, aRefPos.y ), -1, aAccuracy );
509 
510  if( !m_FilledPolysList.count( aLayer ) )
511  return false;
512 
513  return m_FilledPolysList.at( aLayer ).Contains( VECTOR2I( aRefPos.x, aRefPos.y ), -1,
514  aAccuracy );
515 }
516 
517 
518 bool ZONE::HitTestCutout( const VECTOR2I& aRefPos, int* aOutlineIdx, int* aHoleIdx ) const
519 {
520  // Iterate over each outline polygon in the zone and then iterate over
521  // each hole it has to see if the point is in it.
522  for( int i = 0; i < m_Poly->OutlineCount(); i++ )
523  {
524  for( int j = 0; j < m_Poly->HoleCount( i ); j++ )
525  {
526  if( m_Poly->Hole( i, j ).PointInside( aRefPos ) )
527  {
528  if( aOutlineIdx )
529  *aOutlineIdx = i;
530 
531  if( aHoleIdx )
532  *aHoleIdx = j;
533 
534  return true;
535  }
536  }
537  }
538 
539  return false;
540 }
541 
542 
543 void ZONE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
544 {
545  EDA_UNITS units = aFrame->GetUserUnits();
546  wxString msg;
547 
548  if( GetIsRuleArea() )
549  msg = _( "Rule Area" );
550  else if( IsOnCopperLayer() )
551  msg = _( "Copper Zone" );
552  else
553  msg = _( "Non-copper Zone" );
554 
555  // Display Cutout instead of Outline for holes inside a zone (i.e. when num contour !=0).
556  // Check whether the selected corner is in a hole; i.e., in any contour but the first one.
557  if( m_CornerSelection != nullptr && m_CornerSelection->m_contour > 0 )
558  msg << wxT( " " ) << _( "Cutout" );
559 
560  aList.emplace_back( _( "Type" ), msg );
561 
562  if( GetIsRuleArea() )
563  {
564  msg.Empty();
565 
566  if( GetDoNotAllowVias() )
567  AccumulateDescription( msg, _( "No vias" ) );
568 
569  if( GetDoNotAllowTracks() )
570  AccumulateDescription( msg, _( "No tracks" ) );
571 
572  if( GetDoNotAllowPads() )
573  AccumulateDescription( msg, _( "No pads" ) );
574 
576  AccumulateDescription( msg, _( "No copper zones" ) );
577 
579  AccumulateDescription( msg, _( "No footprints" ) );
580 
581  if( !msg.IsEmpty() )
582  aList.emplace_back( MSG_PANEL_ITEM( _( "Restrictions" ), msg ) );
583  }
584  else if( IsOnCopperLayer() )
585  {
586  aList.emplace_back( _( "Net" ), UnescapeString( GetNetname() ) );
587 
588  aList.emplace_back( _( "NetClass" ), UnescapeString( GetNetClass()->GetName() ) );
589 
590  // Display priority level
591  aList.emplace_back( _( "Priority" ), wxString::Format( "%d", GetPriority() ) );
592  }
593 
594  wxString layerDesc;
595  int count = 0;
596 
597  for( PCB_LAYER_ID layer : m_layerSet.Seq() )
598  {
599  if( count == 0 )
600  layerDesc = GetBoard()->GetLayerName( layer );
601 
602  count++;
603  }
604 
605  if( count > 1 )
606  layerDesc.Printf( _( "%s and %d more" ), layerDesc, count - 1 );
607 
608  aList.emplace_back( _( "Layer" ), layerDesc );
609 
610  if( !m_zoneName.empty() )
611  aList.emplace_back( _( "Name" ), m_zoneName );
612 
613  switch( m_fillMode )
614  {
615  case ZONE_FILL_MODE::POLYGONS: msg = _( "Solid" ); break;
616  case ZONE_FILL_MODE::HATCH_PATTERN: msg = _( "Hatched" ); break;
617  default: msg = _( "Unknown" ); break;
618  }
619 
620  aList.emplace_back( _( "Fill Mode" ), msg );
621 
622  msg = MessageTextFromValue( units, m_area, true, EDA_DATA_TYPE::AREA );
623  aList.emplace_back( _( "Filled Area" ), msg );
624 
625  wxString source;
626  int clearance = GetOwnClearance( GetLayer(), &source );
627 
628  aList.emplace_back( wxString::Format( _( "Min Clearance: %s" ),
629  MessageTextFromValue( units, clearance ) ),
630  wxString::Format( _( "(from %s)" ), source ) );
631 
632  // Useful for statistics, especially when zones are complex the number of hatches
633  // and filled polygons can explain the display and DRC calculation time:
634  msg.Printf( wxT( "%d" ), (int) m_borderHatchLines.size() );
635  aList.emplace_back( MSG_PANEL_ITEM( _( "HatchBorder Lines" ), msg ) );
636 
637  PCB_LAYER_ID layer = m_layer;
638 
639  // NOTE: This brings in dependence on PCB_EDIT_FRAME to the qa tests, which isn't ideal.
640  // TODO: Figure out a way for items to know the active layer without the whole edit frame?
641 #if 0
642  if( PCB_EDIT_FRAME* pcbframe = dynamic_cast<PCB_EDIT_FRAME*>( aFrame ) )
643  {
644  if( m_FilledPolysList.count( pcbframe->GetActiveLayer() ) )
645  layer = pcbframe->GetActiveLayer();
646  }
647 #endif
648 
649  if( !GetIsRuleArea() )
650  {
651  auto layer_it = m_FilledPolysList.find( layer );
652 
653  if( layer_it == m_FilledPolysList.end() )
654  layer_it = m_FilledPolysList.begin();
655 
656  if( layer_it != m_FilledPolysList.end() )
657  {
658  msg.Printf( wxT( "%d" ), layer_it->second.TotalVertices() );
659  aList.emplace_back( MSG_PANEL_ITEM( _( "Corner Count" ), msg ) );
660  }
661  }
662 }
663 
664 
665 /* Geometric transforms: */
666 
667 void ZONE::Move( const wxPoint& offset )
668 {
669  /* move outlines */
670  m_Poly->Move( offset );
671 
672  HatchBorder();
673 
674  for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
675  pair.second.Move( offset );
676 
677  for( std::pair<const PCB_LAYER_ID, ZONE_SEGMENT_FILL>& pair : m_FillSegmList )
678  {
679  for( SEG& seg : pair.second )
680  {
681  seg.A += VECTOR2I( offset );
682  seg.B += VECTOR2I( offset );
683  }
684  }
685 }
686 
687 
688 void ZONE::MoveEdge( const wxPoint& offset, int aEdge )
689 {
690  int next_corner;
691 
692  if( m_Poly->GetNeighbourIndexes( aEdge, nullptr, &next_corner ) )
693  {
694  m_Poly->SetVertex( aEdge, m_Poly->CVertex( aEdge ) + VECTOR2I( offset ) );
695  m_Poly->SetVertex( next_corner, m_Poly->CVertex( next_corner ) + VECTOR2I( offset ) );
696  HatchBorder();
697 
698  SetNeedRefill( true );
699  }
700 }
701 
702 
703 void ZONE::Rotate( const wxPoint& aCentre, double aAngle )
704 {
705  aAngle = -DECIDEG2RAD( aAngle );
706 
707  m_Poly->Rotate( aAngle, VECTOR2I( aCentre ) );
708  HatchBorder();
709 
710  /* rotate filled areas: */
711  for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
712  pair.second.Rotate( aAngle, VECTOR2I( aCentre ) );
713 
714  for( std::pair<const PCB_LAYER_ID, ZONE_SEGMENT_FILL>& pair : m_FillSegmList )
715  {
716  for( SEG& seg : pair.second )
717  {
718  wxPoint a( seg.A );
719  RotatePoint( &a, aCentre, aAngle );
720  seg.A = a;
721  wxPoint b( seg.B );
722  RotatePoint( &b, aCentre, aAngle );
723  seg.B = a;
724  }
725  }
726 }
727 
728 
729 void ZONE::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
730 {
731  Mirror( aCentre, aFlipLeftRight );
732  int copperLayerCount = GetBoard()->GetCopperLayerCount();
733 
734  if( GetIsRuleArea() )
735  SetLayerSet( FlipLayerMask( GetLayerSet(), copperLayerCount ) );
736  else
737  SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
738 }
739 
740 
741 void ZONE::Mirror( const wxPoint& aMirrorRef, bool aMirrorLeftRight )
742 {
743  // ZONEs mirror about the x-axis (why?!?)
744  m_Poly->Mirror( aMirrorLeftRight, !aMirrorLeftRight, VECTOR2I( aMirrorRef ) );
745 
746  HatchBorder();
747 
748  for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
749  pair.second.Mirror( aMirrorLeftRight, !aMirrorLeftRight, VECTOR2I( aMirrorRef ) );
750 
751  for( std::pair<const PCB_LAYER_ID, ZONE_SEGMENT_FILL>& pair : m_FillSegmList )
752  {
753  for( SEG& seg : pair.second )
754  {
755  if( aMirrorLeftRight )
756  {
757  MIRROR( seg.A.x, aMirrorRef.x );
758  MIRROR( seg.B.x, aMirrorRef.x );
759  }
760  else
761  {
762  MIRROR( seg.A.y, aMirrorRef.y );
763  MIRROR( seg.B.y, aMirrorRef.y );
764  }
765  }
766  }
767 }
768 
769 
770 ZONE_CONNECTION ZONE::GetPadConnection( PAD* aPad, wxString* aSource ) const
771 {
773  {
774  if( aSource )
775  *aSource = _( "zone" );
776 
777  return m_PadConnection;
778  }
779  else
780  {
781  return aPad->GetEffectiveZoneConnection( aSource );
782  }
783 }
784 
785 
786 void ZONE::RemoveCutout( int aOutlineIdx, int aHoleIdx )
787 {
788  // Ensure the requested cutout is valid
789  if( m_Poly->OutlineCount() < aOutlineIdx || m_Poly->HoleCount( aOutlineIdx ) < aHoleIdx )
790  return;
791 
792  SHAPE_POLY_SET cutPoly( m_Poly->Hole( aOutlineIdx, aHoleIdx ) );
793 
794  // Add the cutout back to the zone
796 
797  SetNeedRefill( true );
798 }
799 
800 
801 void ZONE::AddPolygon( const SHAPE_LINE_CHAIN& aPolygon )
802 {
803  wxASSERT( aPolygon.IsClosed() );
804 
805  // Add the outline as a new polygon in the polygon set
806  if( m_Poly->OutlineCount() == 0 )
807  m_Poly->AddOutline( aPolygon );
808  else
809  m_Poly->AddHole( aPolygon );
810 
811  SetNeedRefill( true );
812 }
813 
814 
815 void ZONE::AddPolygon( std::vector< wxPoint >& aPolygon )
816 {
817  if( aPolygon.empty() )
818  return;
819 
820  SHAPE_LINE_CHAIN outline;
821 
822  // Create an outline and populate it with the points of aPolygon
823  for( const wxPoint& pt : aPolygon)
824  outline.Append( pt );
825 
826  outline.SetClosed( true );
827 
828  AddPolygon( outline );
829 }
830 
831 
832 bool ZONE::AppendCorner( wxPoint aPosition, int aHoleIdx, bool aAllowDuplication )
833 {
834  // Ensure the main outline exists:
835  if( m_Poly->OutlineCount() == 0 )
836  m_Poly->NewOutline();
837 
838  // If aHoleIdx >= 0, the corner musty be added to the hole, index aHoleIdx.
839  // (remember: the index of the first hole is 0)
840  // Return error if if does dot exist.
841  if( aHoleIdx >= m_Poly->HoleCount( 0 ) )
842  return false;
843 
844  m_Poly->Append( aPosition.x, aPosition.y, -1, aHoleIdx, aAllowDuplication );
845 
846  SetNeedRefill( true );
847 
848  return true;
849 }
850 
851 
852 wxString ZONE::GetSelectMenuText( EDA_UNITS aUnits ) const
853 {
854  wxString layerDesc;
855  int count = 0;
856 
857  for( PCB_LAYER_ID layer : m_layerSet.Seq() )
858  {
859  if( count == 0 )
860  layerDesc = GetBoard()->GetLayerName( layer );
861 
862  count++;
863  }
864 
865  if( count > 1 )
866  layerDesc.Printf( _( "%s and %d more" ), layerDesc, count - 1 );
867 
868  // Check whether the selected contour is a hole (contour index > 0)
869  if( m_CornerSelection != nullptr && m_CornerSelection->m_contour > 0 )
870  {
871  if( GetIsRuleArea() )
872  return wxString::Format( _( "Rule Area Cutout on %s" ), layerDesc );
873  else
874  return wxString::Format( _( "Zone Cutout on %s" ), layerDesc );
875  }
876  else
877  {
878  if( GetIsRuleArea() )
879  return wxString::Format( _( "Rule Area on %s" ), layerDesc );
880  else
881  return wxString::Format( _( "Zone %s on %s" ), GetNetnameMsg(), layerDesc );
882  }
883 }
884 
885 
887 {
888  return m_borderHatchPitch;
889 }
890 
891 
892 void ZONE::SetBorderDisplayStyle( ZONE_BORDER_DISPLAY_STYLE aHatchStyle, int aHatchPitch,
893  bool aRebuildHatch )
894 {
895  SetHatchPitch( aHatchPitch );
896  m_borderStyle = aHatchStyle;
897 
898  if( aRebuildHatch )
899  HatchBorder();
900 }
901 
902 
903 void ZONE::SetHatchPitch( int aPitch )
904 {
905  m_borderHatchPitch = aPitch;
906 }
907 
908 
910 {
911  m_borderHatchLines.clear();
912 }
913 
914 
915 // Creates hatch lines inside the outline of the complex polygon
916 // sort function used in ::HatchBorder to sort points by descending wxPoint.x values
917 bool sortEndsByDescendingX( const VECTOR2I& ref, const VECTOR2I& tst )
918 {
919  return tst.x < ref.x;
920 }
921 
922 
924 {
925  UnHatchBorder();
926 
928  || m_borderHatchPitch == 0
929  || m_Poly->IsEmpty() )
930  {
931  return;
932  }
933 
934  // define range for hatch lines
935  int min_x = m_Poly->CVertex( 0 ).x;
936  int max_x = m_Poly->CVertex( 0 ).x;
937  int min_y = m_Poly->CVertex( 0 ).y;
938  int max_y = m_Poly->CVertex( 0 ).y;
939 
940  for( auto iterator = m_Poly->IterateWithHoles(); iterator; iterator++ )
941  {
942  if( iterator->x < min_x )
943  min_x = iterator->x;
944 
945  if( iterator->x > max_x )
946  max_x = iterator->x;
947 
948  if( iterator->y < min_y )
949  min_y = iterator->y;
950 
951  if( iterator->y > max_y )
952  max_y = iterator->y;
953  }
954 
955  // Calculate spacing between 2 hatch lines
956  int spacing;
957 
959  spacing = m_borderHatchPitch;
960  else
961  spacing = m_borderHatchPitch * 2;
962 
963  // set the "length" of hatch lines (the length on horizontal axis)
964  int hatch_line_len = m_borderHatchPitch;
965 
966  // To have a better look, give a slope depending on the layer
967  LAYER_NUM layer = GetLayer();
968  int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1
969  double slope = 0.707106 * slope_flag; // 45 degrees slope
970  int max_a, min_a;
971 
972  if( slope_flag == 1 )
973  {
974  max_a = KiROUND( max_y - slope * min_x );
975  min_a = KiROUND( min_y - slope * max_x );
976  }
977  else
978  {
979  max_a = KiROUND( max_y - slope * max_x );
980  min_a = KiROUND( min_y - slope * min_x );
981  }
982 
983  min_a = (min_a / spacing) * spacing;
984 
985  // calculate an offset depending on layer number,
986  // for a better look of hatches on a multilayer board
987  int offset = (layer * 7) / 8;
988  min_a += offset;
989 
990  // loop through hatch lines
991  #define MAXPTS 200 // Usually we store only few values per one hatch line
992  // depending on the complexity of the zone outline
993 
994  static std::vector<VECTOR2I> pointbuffer;
995  pointbuffer.clear();
996  pointbuffer.reserve( MAXPTS + 2 );
997 
998  for( int a = min_a; a < max_a; a += spacing )
999  {
1000  // get intersection points for this hatch line
1001 
1002  // Note: because we should have an even number of intersections with the
1003  // current hatch line and the zone outline (a closed polygon,
1004  // or a set of closed polygons), if an odd count is found
1005  // we skip this line (should not occur)
1006  pointbuffer.clear();
1007 
1008  // Iterate through all vertices
1009  for( auto iterator = m_Poly->IterateSegmentsWithHoles(); iterator; iterator++ )
1010  {
1011  double x, y;
1012  bool ok;
1013 
1014  SEG segment = *iterator;
1015 
1016  ok = FindLineSegmentIntersection( a, slope,
1017  segment.A.x, segment.A.y,
1018  segment.B.x, segment.B.y,
1019  x, y );
1020 
1021  if( ok )
1022  {
1023  VECTOR2I point( KiROUND( x ), KiROUND( y ) );
1024  pointbuffer.push_back( point );
1025  }
1026 
1027  if( pointbuffer.size() >= MAXPTS ) // overflow
1028  {
1029  wxASSERT( 0 );
1030  break;
1031  }
1032  }
1033 
1034  // ensure we have found an even intersection points count
1035  // because intersections are the ends of segments
1036  // inside the polygon(s) and a segment has 2 ends.
1037  // if not, this is a strange case (a bug ?) so skip this hatch
1038  if( pointbuffer.size() % 2 != 0 )
1039  continue;
1040 
1041  // sort points in order of descending x (if more than 2) to
1042  // ensure the starting point and the ending point of the same segment
1043  // are stored one just after the other.
1044  if( pointbuffer.size() > 2 )
1045  sort( pointbuffer.begin(), pointbuffer.end(), sortEndsByDescendingX );
1046 
1047  // creates lines or short segments inside the complex polygon
1048  for( unsigned ip = 0; ip < pointbuffer.size(); ip += 2 )
1049  {
1050  int dx = pointbuffer[ip + 1].x - pointbuffer[ip].x;
1051 
1052  // Push only one line for diagonal hatch,
1053  // or for small lines < twice the line length
1054  // else push 2 small lines
1056  || std::abs( dx ) < 2 * hatch_line_len )
1057  {
1058  m_borderHatchLines.emplace_back( SEG( pointbuffer[ip], pointbuffer[ ip + 1] ) );
1059  }
1060  else
1061  {
1062  double dy = pointbuffer[ip + 1].y - pointbuffer[ip].y;
1063  slope = dy / dx;
1064 
1065  if( dx > 0 )
1066  dx = hatch_line_len;
1067  else
1068  dx = -hatch_line_len;
1069 
1070  int x1 = KiROUND( pointbuffer[ip].x + dx );
1071  int x2 = KiROUND( pointbuffer[ip + 1].x - dx );
1072  int y1 = KiROUND( pointbuffer[ip].y + dx * slope );
1073  int y2 = KiROUND( pointbuffer[ip + 1].y - dx * slope );
1074 
1075  m_borderHatchLines.emplace_back( SEG( pointbuffer[ip].x, pointbuffer[ip].y, x1, y1 ) );
1076 
1077  m_borderHatchLines.emplace_back( SEG( pointbuffer[ip+1].x, pointbuffer[ip+1].y, x2, y2 ) );
1078  }
1079  }
1080  }
1081 }
1082 
1083 
1085 {
1086  return Mils2iu( 20 );
1087 }
1088 
1089 
1091 {
1092  return add_zone_xpm;
1093 }
1094 
1095 
1097 {
1098  assert( aImage->Type() == PCB_ZONE_T );
1099 
1100  std::swap( *((ZONE*) this), *((ZONE*) aImage) );
1101 }
1102 
1103 
1105 {
1106  if( aLayer == UNDEFINED_LAYER )
1107  {
1108  for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
1109  pair.second.CacheTriangulation();
1110  }
1111  else
1112  {
1113  if( m_FilledPolysList.count( aLayer ) )
1115  }
1116 }
1117 
1118 
1119 bool ZONE::IsIsland( PCB_LAYER_ID aLayer, int aPolyIdx ) const
1120 {
1121  if( GetNetCode() < 1 )
1122  return true;
1123 
1124  if( !m_insulatedIslands.count( aLayer ) )
1125  return false;
1126 
1127  return m_insulatedIslands.at( aLayer ).count( aPolyIdx );
1128 }
1129 
1130 
1131 void ZONE::GetInteractingZones( PCB_LAYER_ID aLayer, std::vector<ZONE*>* aZones ) const
1132 {
1133  int epsilon = Millimeter2iu( 0.001 );
1134 
1135  for( ZONE* candidate : GetBoard()->Zones() )
1136  {
1137  if( candidate == this )
1138  continue;
1139 
1140  if( !candidate->GetLayerSet().test( aLayer ) )
1141  continue;
1142 
1143  if( candidate->GetIsRuleArea() )
1144  continue;
1145 
1146  if( candidate->GetNetCode() != GetNetCode() )
1147  continue;
1148 
1149  for( auto iter = m_Poly->CIterate(); iter; iter++ )
1150  {
1151  if( candidate->m_Poly->Collide( iter.Get(), epsilon ) )
1152  {
1153  aZones->push_back( candidate );
1154  break;
1155  }
1156  }
1157  }
1158 }
1159 
1160 
1162  SHAPE_POLY_SET* aBoardOutline,
1163  SHAPE_POLY_SET* aSmoothedPolyWithApron ) const
1164 {
1165  if( GetNumCorners() <= 2 ) // malformed zone. polygon calculations will not like it ...
1166  return false;
1167 
1168  int zoneClearance = m_ZoneClearance;
1169 
1170  if( GetIsRuleArea() )
1171  {
1172  // We like keepouts just the way they are....
1173  aSmoothedPoly = *m_Poly;
1174  return true;
1175  }
1176  else if( !IsOnCopperLayer() )
1177  {
1178  // Non-copper zones don't have electrical clearances
1179  zoneClearance = 0;
1180  }
1181 
1182  BOARD* board = GetBoard();
1183  int edgeClearance = 0;
1184  int maxError = ARC_HIGH_DEF;
1185  bool keepExternalFillets = false;
1186 
1187  if( board )
1188  {
1189  BOARD_DESIGN_SETTINGS& bds = board->GetDesignSettings();
1190 
1191  DRC_CONSTRAINT c = bds.m_DRCEngine->EvalRules( EDGE_CLEARANCE_CONSTRAINT, this, nullptr,
1192  aLayer );
1193  edgeClearance = c.Value().Min();
1194  maxError = bds.m_MaxError;
1195  keepExternalFillets = bds.m_ZoneKeepExternalFillets;
1196  }
1197 
1198  auto smooth = [&]( SHAPE_POLY_SET& aPoly )
1199  {
1200  switch( m_cornerSmoothingType )
1201  {
1203  aPoly = aPoly.Chamfer( (int) m_cornerRadius );
1204  break;
1205 
1207  {
1208  aPoly = aPoly.Fillet( (int) m_cornerRadius, maxError );
1209  break;
1210  }
1211 
1212  default:
1213  break;
1214  }
1215  };
1216 
1217  std::vector<ZONE*> interactingZones;
1218  GetInteractingZones( aLayer, &interactingZones );
1219 
1220  SHAPE_POLY_SET* maxExtents = m_Poly;
1221  SHAPE_POLY_SET withFillets;
1222 
1223  aSmoothedPoly = *m_Poly;
1224 
1225  // Should external fillets (that is, those applied to concave corners) be kept? While it
1226  // seems safer to never have copper extend outside the zone outline, 5.1.x and prior did
1227  // indeed fill them so we leave the mode available.
1228  if( keepExternalFillets )
1229  {
1230  withFillets = *m_Poly;
1231  smooth( withFillets );
1232  withFillets.BooleanAdd( *m_Poly, SHAPE_POLY_SET::PM_FAST );
1233  maxExtents = &withFillets;
1234  }
1235 
1236  for( ZONE* zone : interactingZones )
1237  aSmoothedPoly.BooleanAdd( *zone->Outline(), SHAPE_POLY_SET::PM_FAST );
1238 
1239  if( aBoardOutline )
1240  {
1241  SHAPE_POLY_SET poly = *aBoardOutline;
1242  poly.Deflate( std::max( zoneClearance, edgeClearance ), 16 );
1244  }
1245 
1246  smooth( aSmoothedPoly );
1247 
1248  if( aSmoothedPolyWithApron )
1249  {
1250  SHAPE_POLY_SET poly = *maxExtents;
1251  poly.Inflate( m_ZoneMinThickness, 16 );
1252  *aSmoothedPolyWithApron = aSmoothedPoly;
1253  aSmoothedPolyWithApron->BooleanIntersection( poly, SHAPE_POLY_SET::PM_FAST );
1254  }
1255 
1256  aSmoothedPoly.BooleanIntersection( *maxExtents, SHAPE_POLY_SET::PM_FAST );
1257 
1258  return true;
1259 }
1260 
1261 
1263 {
1264  m_area = 0.0;
1265 
1266  // Iterate over each outline polygon in the zone and then iterate over
1267  // each hole it has to compute the total area.
1268  for( std::pair<const PCB_LAYER_ID, SHAPE_POLY_SET>& pair : m_FilledPolysList )
1269  {
1270  SHAPE_POLY_SET& poly = pair.second;
1271 
1272  for( int i = 0; i < poly.OutlineCount(); i++ )
1273  {
1274  m_area += poly.Outline( i ).Area();
1275 
1276  for( int j = 0; j < poly.HoleCount( i ); j++ )
1277  m_area -= poly.Hole( i, j ).Area();
1278  }
1279  }
1280 
1281  return m_area;
1282 }
1283 
1284 
1290 void ZONE::TransformSmoothedOutlineToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aClearance,
1291  SHAPE_POLY_SET* aBoardOutline ) const
1292 {
1293  // Creates the zone outline polygon (with holes if any)
1294  SHAPE_POLY_SET polybuffer;
1295  BuildSmoothedPoly( polybuffer, GetLayer(), aBoardOutline );
1296 
1297  // Calculate the polygon with clearance
1298  // holes are linked to the main outline, so only one polygon is created.
1299  if( aClearance )
1300  {
1301  BOARD* board = GetBoard();
1302  int maxError = ARC_HIGH_DEF;
1303 
1304  if( board )
1305  maxError = board->GetDesignSettings().m_MaxError;
1306 
1307  int segCount = GetArcToSegmentCount( aClearance, maxError, 360.0 );
1308  polybuffer.Inflate( aClearance, segCount );
1309  }
1310 
1311  polybuffer.Fracture( SHAPE_POLY_SET::PM_FAST );
1312  aCornerBuffer.Append( polybuffer );
1313 }
1314 
1315 
1316 //
1317 /********* FP_ZONE **************/
1318 //
1320  ZONE( aParent, true )
1321 {
1322  // in a footprint, net classes are not managed.
1323  // so set the net to NETINFO_LIST::ORPHANED_ITEM
1324  SetNetCode( -1, true );
1325 }
1326 
1327 
1328 FP_ZONE::FP_ZONE( const FP_ZONE& aZone ) :
1329  ZONE( aZone.GetParent(), true )
1330 {
1331  InitDataFromSrcInCopyCtor( aZone );
1332 }
1333 
1334 
1336 {
1337  ZONE::operator=( aOther );
1338  return *this;
1339 }
1340 
1341 
1343 {
1344  return new FP_ZONE( *this );
1345 }
1346 
1347 
1348 double FP_ZONE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
1349 {
1350  constexpr double HIDE = (double)std::numeric_limits<double>::max();
1351 
1352  if( !aView )
1353  return 0;
1354 
1355  if( !aView->IsLayerVisible( LAYER_ZONES ) )
1356  return HIDE;
1357 
1358  bool flipped = GetParent() && GetParent()->GetLayer() == B_Cu;
1359 
1360  // Handle Render tab switches
1361  if( !flipped && !aView->IsLayerVisible( LAYER_MOD_FR ) )
1362  return HIDE;
1363 
1364  if( flipped && !aView->IsLayerVisible( LAYER_MOD_BK ) )
1365  return HIDE;
1366 
1367  // Other layers are shown without any conditions
1368  return 0.0;
1369 }
1370 
1371 
1372 std::shared_ptr<SHAPE> ZONE::GetEffectiveShape( PCB_LAYER_ID aLayer ) const
1373 {
1374  std::shared_ptr<SHAPE> shape;
1375 
1376  if( m_FilledPolysList.find( aLayer ) == m_FilledPolysList.end() )
1377  {
1378  shape = std::make_shared<SHAPE_NULL>();
1379  }
1380  else
1381  {
1382  shape.reset( m_FilledPolysList.at( aLayer ).Clone() );
1383  }
1384 
1385  return shape;
1386 }
1387 
1388 
1389 static struct ZONE_DESC
1390 {
1392  {
1394  .Map( ZONE_CONNECTION::INHERITED, _HKI( "Inherited" ) )
1395  .Map( ZONE_CONNECTION::NONE, _HKI( "None" ) )
1396  .Map( ZONE_CONNECTION::THERMAL, _HKI( "Thermal reliefs" ) )
1397  .Map( ZONE_CONNECTION::FULL, _HKI( "Solid" ) )
1398  .Map( ZONE_CONNECTION::THT_THERMAL, _HKI( "Reliefs for PTH" ) );
1399 
1401  REGISTER_TYPE( ZONE );
1403  propMgr.AddProperty( new PROPERTY<ZONE, unsigned>( _HKI( "Priority" ),
1405  //propMgr.AddProperty( new PROPERTY<ZONE, bool>( "Filled",
1406  //&ZONE::SetIsFilled, &ZONE::IsFilled ) );
1407  propMgr.AddProperty( new PROPERTY<ZONE, wxString>( _HKI( "Name" ),
1409  propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Clearance" ),
1412  propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Min Width" ),
1415  propMgr.AddProperty( new PROPERTY_ENUM<ZONE, ZONE_CONNECTION>( _HKI( "Pad Connections" ),
1417  propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thermal Clearance" ),
1420  propMgr.AddProperty( new PROPERTY<ZONE, int>( _HKI( "Thermal Spoke Width" ),
1423  }
1424 } _ZONE_DESC;
1425 
ZONE_BORDER_DISPLAY_STYLE m_borderStyle
Definition: zone.h:946
int TotalVertices() const
Delete aIdx-th polygon from the set.
static LSET AllCuMask(int aCuLayerCount=MAX_CU_LAYERS)
Return a mask holding the requested number of Cu PCB_LAYER_IDs.
Definition: lset.cpp:750
int GetNumCorners(void) const
Access to m_Poly parameters.
Definition: zone.h:530
Virtual layers for stacking zones and tracks on a given copper layer.
ZONE_CONNECTION
How pads are covered by copper in zone.
Definition: zones.h:41
ZONE_CONNECTION GetPadConnection() const
Definition: zone.h:244
wxString MessageTextFromValue(EDA_UNITS aUnits, int aValue, bool aAddUnitLabel, EDA_DATA_TYPE aType)
Convert a value to a string using double notation.
Definition: base_units.cpp:125
bool m_doNotAllowFootprints
Definition: zone.h:873
void SetCornerRadius(unsigned int aRadius)
Definition: zone.cpp:358
void CacheTriangulation(PCB_LAYER_ID aLayer=UNDEFINED_LAYER)
(re)create a list of triangles that "fill" the solid areas.
Definition: zone.cpp:1104
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:66
unsigned int m_cornerRadius
Definition: zone.h:848
void TransformSmoothedOutlineToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearance, SHAPE_POLY_SET *aBoardOutline) const
Function TransformSmoothedOutlineToPolygon Convert the outlines shape to a polygon with no holes infl...
Definition: zone.cpp:1290
#define TYPE_HASH(x)
Definition: property.h:57
LSET FlipLayerMask(LSET aMask, int aCopperLayersCount)
Calculate the mask layer when flipping a footprint.
Definition: lset.cpp:567
ENUM_TO_WXANY(ZONE_CONNECTION)
int OutlineCount() const
Return the number of vertices in a given outline/hole.
void RemoveCutout(int aOutlineIdx, int aHoleIdx)
Remove a cutout from the zone.
Definition: zone.cpp:786
void SetZoneName(const wxString &aName)
Definition: zone.h:132
bool GetDoNotAllowFootprints() const
Definition: zone.h:760
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
Definition: board.cpp:342
PNG memory record (file in memory).
Definition: bitmap_def.h:29
void SetDoNotAllowTracks(bool aEnable)
Definition: zone.h:765
void UnHatchBorder()
Function UnHatchBorder clears the zone's hatch.
Definition: zone.cpp:909
ZONE_FILL_MODE m_fillMode
How to fill areas: ZONE_FILL_MODE::POLYGONS => use solid polygons ZONE_FILL_MODE::HATCH_PATTERN => us...
Definition: zone.h:905
SEGMENT_ITERATOR IterateSegmentsWithHoles()
Return an iterator object, for the aOutline-th outline in the set (with holes).
int m_ZoneClearance
Definition: zone.h:876
unsigned GetPriority() const
Function GetPriority.
Definition: zone.h:124
void BooleanAdd(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset difference For aFastMode meaning, see function booleanOp.
NETCLASS * GetNetClass() const override
Return the NETCLASS for this item.
Definition: zone.h:88
bool GetIsRuleArea() const
Accessors to parameters used in Rule Area zones:
Definition: zone.h:755
BITMAP_DEF GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: zone.cpp:1090
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:82
int m_cornerSmoothingType
Definition: zone.h:847
MINOPTMAX< int > & Value()
Definition: drc_rule.h:122
void SetBorderDisplayStyle(ZONE_BORDER_DISPLAY_STYLE aHatchStyle, int aHatchPitch, bool aRebuildHatch)
Function SetBorderDisplayStyle sets all hatch parameters for the zone.
Definition: zone.cpp:892
SHAPE_POLY_SET * m_Poly
Outline of the zone.
Definition: zone.h:846
int GetBorderHatchPitch() const
HatchBorder related methods.
Definition: zone.cpp:886
wxString m_zoneName
An optional unique name for this zone, used for identifying it in DRC checking.
Definition: zone.h:851
Control for copper zone opacity/visibility (color ignored)
const VECTOR2I & CVertex(int aIndex, int aOutline, int aHole) const
Return the aGlobalIndex-th vertex in the poly set.
int m_hatchSmoothingLevel
Definition: zone.h:909
void SetLayerSet(LSET aLayerSet) override
Definition: zone.cpp:243
ZONE_CONNECTION m_PadConnection
Definition: zone.h:875
bool GetDoNotAllowVias() const
Definition: zone.h:757
double m_area
Definition: zone.h:955
bool m_doNotAllowTracks
Definition: zone.h:871
PCB_LAYER_ID FlipLayer(PCB_LAYER_ID aLayerId, int aCopperLayersCount)
Definition: lset.cpp:521
bool IsEmpty() const
~ZONE()
Definition: zone.cpp:98
long long int m_minIslandArea
When island removal mode is set to AREA, islands below this area will be removed.
Definition: zone.h:886
double m_hatchOrientation
Definition: zone.h:908
virtual LSET GetLayerSet() const override
Return a std::bitset of all layers on which the item physically resides.
Definition: zone.cpp:288
show footprints on back
static ENUM_MAP< T > & Instance()
Definition: property.h:508
bool CommonLayerExists(const LSET aLayerSet) const
Function CommonLayerExist Test if this zone shares a common layer with the given layer set.
Definition: zone.cpp:227
bool SetNetCode(int aNetCode, bool aNoAssert)
Set net using a net code.
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
SHAPE_LINE_CHAIN & Hole(int aOutline, int aHole)
Return the aIndex-th subpolygon in the set.
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Definition: sch_symbol.cpp:69
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:951
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, PCB_LAYER_ID aLayer, SHAPE_POLY_SET *aBoardOutline, SHAPE_POLY_SET *aSmoothedPolyWithApron=nullptr) const
Function GetSmoothedPoly.
Definition: zone.cpp:1161
wxString GetNetname() const
virtual bool IsOnLayer(PCB_LAYER_ID) const override
Test to see if this object is on the given layer.
Definition: zone.cpp:313
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Definition: board.h:584
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Return true if a given subpolygon contains the point aP.
int GetEffectiveThermalGap(wxString *aSource=nullptr) const
Return the effective thermal gap having resolved any inheritance.
Definition: pcbnew/pad.cpp:832
T Min() const
Definition: minoptmax.h:33
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:228
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Perform outline inflation/deflation.
The base class for create windows for drawing purpose.
MD5_HASH GetHashValue(PCB_LAYER_ID aLayer)
Definition: zone.cpp:379
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:543
VECTOR2< int > VECTOR2I
Definition: vector2d.h:623
LSEQ Seq(const PCB_LAYER_ID *aWishListSequence, unsigned aCount) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:411
void SetPriority(unsigned aPriority)
Function SetPriority.
Definition: zone.h:118
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
ZONE(BOARD_ITEM_CONTAINER *parent, bool aInFP=false)
The ctor to build ZONE, but comaptible with FP_ZONE requirement.
Definition: zone.cpp:42
int m_hatchThickness
Definition: zone.h:906
#define REGISTER_TYPE(x)
Definition: property_mgr.h:249
bool HitTestFilledArea(PCB_LAYER_ID aLayer, const wxPoint &aRefPos, int aAccuracy=0) const
Function HitTestFilledArea tests if the given wxPoint is within the bounds of a filled area of this z...
Definition: zone.cpp:503
bool Contains(const wxPoint &aPoint) const
Definition: eda_rect.cpp:57
LSET m_layerSet
Definition: zone.h:853
virtual void SwapData(BOARD_ITEM *aImage) override
Swap data between aItem and aImage.
Definition: zone.cpp:1096
struct SHAPE_POLY_SET::VERTEX_INDEX VERTEX_INDEX
Structure to hold the necessary information in order to index a vertex on a SHAPE_POLY_SET object: th...
bool HitTestForCorner(const wxPoint &refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX &aCornerHit) const
Function HitTestForCorner tests if the given wxPoint is near a corner.
Definition: zone.cpp:422
virtual void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
Definition: zone.cpp:729
void Mirror(bool aX=true, bool aY=false, const VECTOR2I &aRef={ 0, 0 })
Mirror the line points about y or x (or both)
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
bool m_doNotAllowVias
Definition: zone.h:870
void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:40
void SetIsRuleArea(bool aEnable)
Definition: zone.h:762
std::map< PCB_LAYER_ID, ZONE_SEGMENT_FILL > m_FillSegmList
Segments used to fill the zone (#m_FillMode ==1 ), when fill zone by segment is used.
Definition: zone.h:926
show footprints on front
int GetThermalReliefGap() const
Definition: zone.h:195
bool GetNeighbourIndexes(int aGlobalIndex, int *aPrevious, int *aNext)
Return the global indexes of the previous and the next corner of the aGlobalIndex-th corner of a cont...
int GetEffectiveThermalSpokeWidth(wxString *aSource=nullptr) const
Return the effective thermal spoke width having resolved any inheritance.
Definition: pcbnew/pad.cpp:813
void Rotate(const wxPoint &aCentre, double aAngle) override
Function Rotate Move the outlines.
Definition: zone.cpp:703
void SetVertex(const VERTEX_INDEX &aIndex, const VECTOR2I &aPos)
Accessor function to set the position of a specific point.
void GetInteractingZones(PCB_LAYER_ID aLayer, std::vector< ZONE * > *aZones) const
Some intersecting zones, despite being on the same layer with the same net, cannot be merged due to o...
Definition: zone.cpp:1131
bool HitTestCutout(const VECTOR2I &aRefPos, int *aOutlineIdx=nullptr, int *aHoleIdx=nullptr) const
Tests if the given point is contained within a cutout of the zone.
Definition: zone.cpp:518
std::map< PCB_LAYER_ID, bool > m_fillFlags
Definition: zone.h:941
void AccumulateDescription(wxString &aDesc, const wxString &aItem)
Utility to build comma separated lists in messages.
Definition: kicad_string.h:299
void SetClosed(bool aClosed)
Function SetClosed()
bool GetDoNotAllowPads() const
Definition: zone.h:759
void MoveEdge(const wxPoint &offset, int aEdge)
Function MoveEdge Move the outline Edge.
Definition: zone.cpp:688
PCB_LAYER_ID
A quick note on layer IDs:
Display value expressed in distance units (mm/inch)
Definition: property.h:51
bool GetDoNotAllowCopperPour() const
Definition: zone.h:756
virtual void ViewGetLayers(int aLayers[], int &aCount) const override
Return the all the layers within the VIEW the object is painted on.
Definition: zone.cpp:294
LSET is a set of PCB_LAYER_IDs.
pads are covered by copper
int GetLocalClearance() const
Definition: zone.h:160
int GetMinThickness() const
Definition: zone.h:247
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox (virtual)
Definition: zone.cpp:319
#define NULL
MD5_HASH GetHash() const
void Move(const VECTOR2I &aVector) override
bool IsClosed() const override
Function IsClosed()
static int GetDefaultHatchPitch()
Function GetDefaultHatchPitchMils.
Definition: zone.cpp:1084
void ExportSetting(ZONE &aTarget, bool aFullExport=true) const
Function ExportSetting copy settings to a given zone.
void SetDoNotAllowPads(bool aEnable)
Definition: zone.h:766
void HatchBorder()
Function HatchBorder computes the hatch lines depending on the hatch parameters and stores it in the ...
Definition: zone.cpp:923
ITERATOR IterateWithHoles(int aOutline)
Represent a set of closed polygons.
virtual std::shared_ptr< SHAPE > GetEffectiveShape(PCB_LAYER_ID aLayer=UNDEFINED_LAYER) const override
Some pad shapes can be complex (rounded/chamfered rectangle), even without considering custom shapes.
Definition: zone.cpp:1372
bool HitTest(const wxPoint &aPosition, int aAccuracy=0) const override
Function HitTest tests if a point is near an outline edge or a corner of this zone.
Definition: zone.cpp:397
SHAPE_LINE_CHAIN & Outline(int aIndex)
virtual PCB_LAYER_ID GetLayer() const override
Return the primary layer this item is on.
Definition: zone.cpp:215
void SetSelectedCorner(int aCorner)
Definition: zone.h:288
ZONE_CONNECTION GetEffectiveZoneConnection(wxString *aSource=nullptr) const
Return the zone connection in effect (either locally overridden or overridden in the parent footprint...
Definition: pcbnew/pad.cpp:792
virtual BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
Definition: board_item.cpp:46
int GetLocalFlags() const
Definition: zone.h:308
bool PointInside(const VECTOR2I &aPt, int aAccuracy=0, bool aUseBBoxCache=false) const
Check if point aP lies inside a polygon (any type) defined by the line chain.
bool GetDoNotAllowTracks() const
Definition: zone.h:758
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
int m_thermalReliefGap
Definition: zone.h:897
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
bool m_hv45
Definition: zone.h:953
static LSET InternalCuMask()
Return a complete set of internal copper layers which is all Cu layers except F_Cu and B_Cu.
Definition: lset.cpp:710
void InitDataFromSrcInCopyCtor(const ZONE &aZone)
Copy aZone data to me.
Definition: zone.cpp:105
SHAPE_POLY_SET::VERTEX_INDEX * m_CornerSelection
The index of the corner being moved or nullptr if no corner is selected.
Definition: zone.h:919
ISLAND_REMOVAL_MODE m_islandRemovalMode
Definition: zone.h:880
void SetDoNotAllowVias(bool aEnable)
Definition: zone.h:764
a few functions useful in geometry calculations.
#define MAXPTS
ZONE handles a list of polygons defining a copper zone.
Definition: zone.h:57
class ZONE, a copper pour area
Definition: typeinfo.h:105
bool sortEndsByDescendingX(const VECTOR2I &ref, const VECTOR2I &tst)
Definition: zone.cpp:917
static SHAPE_POLY_SET g_nullPoly
Definition: zone.cpp:376
void SetMinThickness(int aMinThickness)
Definition: zone.h:248
std::map< PCB_LAYER_ID, MD5_HASH > m_filledPolysHash
A hash value used in zone filling calculations to see if the filled areas are up to date.
Definition: zone.h:944
virtual const ZONE_SETTINGS & GetZoneSettings() const
Fetch the zone settings for this container.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Perform boolean polyset union between a and b, store the result in it self For aFastMode meaning,...
int NewOutline()
Creates a new hole in a given outline.
int HoleCount(int aOutline) const
Return the reference to aIndex-th outline in the set.
int m_ZoneMinThickness
Definition: zone.h:877
CONST_ITERATOR CIterate(int aFirst, int aLast, bool aIterateHoles=false) const
EDA_ITEM & operator=(const EDA_ITEM &aItem)
Assign the members of aItem to another object.
Definition: eda_item.cpp:193
void Fracture(POLYGON_MODE aFastMode)
Convert a single outline slitted ("fractured") polygon into a set ouf outlines with holes.
int AddHole(const SHAPE_LINE_CHAIN &aHole, int aOutline=-1)
Return the area of this poly set.
LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
Thermal relief only for THT pads.
std::map< PCB_LAYER_ID, SHAPE_POLY_SET > m_RawPolysList
Definition: zone.h:937
int LAYER_NUM
This can be replaced with int and removed.
wxString GetNetnameMsg() const
void BuildHashValue(PCB_LAYER_ID aLayer)
Build the hash value of m_FilledPolysList, and store it internally in m_filledPolysHash.
Definition: zone.cpp:388
bool m_isRuleArea
Definition: zone.h:864
Some functions to handle hotkeys in KiCad.
void Move(const wxPoint &offset) override
Function Move Move the outlines.
Definition: zone.cpp:667
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
int m_borderHatchPitch
Definition: zone.h:947
Definition: seg.h:41
EDA_UNITS
Definition: eda_units.h:38
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new hole to the given outline (default: last) and returns its index.
void Normalize()
Ensures that the height ant width are positive.
Definition: eda_rect.cpp:35
Use thermal relief for pads.
std::vector< SEG > m_borderHatchLines
Definition: zone.h:948
void SetLocalFlags(int aFlags)
Definition: zone.h:309
bool CollideEdge(const VECTOR2I &aPoint, VERTEX_INDEX &aClosestVertex, int aClearance=0) const
Check whether aPoint collides with any edge of any of the contours of the polygon.
void SetPadConnection(ZONE_CONNECTION aPadConnection)
Definition: zone.h:245
bool AppendCorner(wxPoint aPosition, int aHoleIdx, bool aAllowDuplication=false)
Add a new corner to the zone outline (to the main outline or a hole)
Definition: zone.cpp:832
int m_hatchBorderAlgorithm
Definition: zone.h:915
bool HitTestForEdge(const wxPoint &refPos, int aAccuracy, SHAPE_POLY_SET::VERTEX_INDEX &aCornerHit) const
Function HitTestForEdge tests if the given wxPoint is near a segment defined by 2 corners.
Definition: zone.cpp:436
ZONE_DESC()
Definition: zone.cpp:1391
wxPoint GetPosition() const override
Definition: zone.cpp:209
bool m_isFilled
True when a zone was filled, false after deleting the filled areas.
Definition: zone.h:889
FP_ZONE & operator=(const FP_ZONE &aOther)
Definition: zone.cpp:1335
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:189
void SetDoNotAllowCopperPour(bool aEnable)
Definition: zone.h:763
bool IsIsland(PCB_LAYER_ID aLayer, int aPolyIdx) const
Checks if a given filled polygon is an insulated island.
Definition: zone.cpp:1119
#define _(s)
Definition: 3d_actions.cpp:33
SHAPE_LINE_CHAIN.
NETINFO_ITEM * m_netinfo
Store all information about the net that item belongs to.
void SetHatchPitch(int aPitch)
Function SetHatchPitch sets the hatch pitch parameter for the zone.
Definition: zone.cpp:903
wxString UnescapeString(const wxString &aSource)
Definition: string.cpp:150
int m_hatchGap
Definition: zone.h:907
void AddProperty(PROPERTY_BASE *aProperty)
Register a property.
int GetCopperLayerCount() const
Definition: board.cpp:435
class ZONE, managed by a footprint
Definition: typeinfo.h:94
VECTOR2I A
Definition: seg.h:49
const VECTOR2I & GetCornerPosition(int aCornerIndex) const
Definition: zone.h:570
Handle the component boundary box.
Definition: eda_rect.h:42
double DECIDEG2RAD(double deg)
Definition: trigo.h:235
FP_ZONE(BOARD_ITEM_CONTAINER *aParent)
Definition: zone.cpp:1319
The main frame for Pcbnew.
void Mirror(const wxPoint &aMirrorRef, bool aMirrorLeftRight)
Function Mirror Mirror the outlines , relative to a given horizontal axis the layer is not changed.
Definition: zone.cpp:741
bool IsOnCopperLayer() const override
Function IsOnCopperLayer.
Definition: zone.cpp:221
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:68
bool m_doNotAllowCopperPour
Definition: zone.h:869
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:149
Pads are not covered.
virtual int GetOwnClearance(PCB_LAYER_ID aLayer, wxString *aSource=nullptr) const
Return an item's "own" clearance in internal units.
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: zone.cpp:180
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
PCB_LAYER_ID m_layer
Definition: board_item.h:363
int m_fillVersion
Definition: zone.h:878
void SetThermalReliefGap(int aThermalReliefGap)
Definition: zone.h:188
const BITMAP_OPAQUE add_zone_xpm[1]
Definition: add_zone.cpp:25
ZONE_BORDER_DISPLAY_STYLE
Zone border styles.
Definition: zone_settings.h:46
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:63
virtual void SetLayer(PCB_LAYER_ID aLayer) override
Set the layer this item is on.
Definition: zone.cpp:235
void SetNeedRefill(bool aNeedRefill)
Definition: zone.h:241
double m_hatchHoleMinArea
Definition: zone.h:914
double CalculateFilledArea()
Compute the area currently occupied by the zone fill.
Definition: zone.cpp:1262
void SetLocalClearance(int aClearance)
Definition: zone.h:161
bool m_needRefill
False when a zone was refilled, true after changes in zone params.
Definition: zone.h:895
void AddPolygon(std::vector< wxPoint > &aPolygon)
add a polygon to the zone outline if the zone outline is empty, this is the main outline else it is a...
Definition: zone.cpp:815
int GetThermalReliefSpokeWidth() const
Definition: zone.h:205
Abstract interface for BOARD_ITEMs capable of storing other items inside.
EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:54
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:67
ZONE & operator=(const ZONE &aOther)
Definition: zone.cpp:88
wxString GetSelectMenuText(EDA_UNITS aUnits) const override
Return the text to display to be used in the selection clarification context menu when multiple items...
Definition: zone.cpp:852
Definition: pad.h:60
STATUS_FLAGS m_flags
Definition: eda_item.h:530
bool UnFill()
Function UnFill Removes the zone filling.
Definition: zone.cpp:186
wxString GetZoneName() const
Definition: zone.h:131
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: zone.cpp:1348
BOARD_ITEM_CONTAINER * GetParent() const
Definition: board_item.h:168
bool m_forceVisible
Definition: eda_item.h:529
static constexpr int Millimeter2iu(double mm)
#define _HKI(x)
std::map< PCB_LAYER_ID, SHAPE_POLY_SET > m_FilledPolysList
Definition: zone.h:936
virtual PCB_LAYER_ID GetLayer() const
Return the primary layer this item is on.
Definition: board_item.h:173
const BOX2I BBox(int aClearance=0) const override
Compute a bounding box of the shape, with a margin of aClearance a collision.
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: zone.cpp:305
unsigned m_priority
Definition: zone.h:859
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
double m_hatchSmoothingValue
Definition: zone.h:913
FP_ZONE is a specialization of ZONE for use in footprints.
Definition: zone.h:965
bool CollideVertex(const VECTOR2I &aPoint, VERTEX_INDEX &aClosestVertex, int aClearance=0) const
Check whether aPoint collides with any vertex of any of the contours of the polygon.
std::shared_ptr< DRC_ENGINE > m_DRCEngine
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
int m_thermalReliefSpokeWidth
Definition: zone.h:898
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Inflate the rectangle horizontally by dx and vertically by dy.
Definition: eda_rect.cpp:363
static struct ZONE_DESC _ZONE_DESC
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
void SetDoNotAllowFootprints(bool aEnable)
Definition: zone.h:767
bool GetFilledPolysUseThickness() const
Definition: zone.h:712
Container for design settings for a BOARD object.
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:404
int Append(int x, int y, int aOutline=-1, int aHole=-1, bool aAllowDuplication=false)
Add a new vertex to the contour indexed by aOutline and aHole (defaults to the outline of the last po...
void SetThermalReliefSpokeWidth(int aThermalReliefSpokeWidth)
Definition: zone.h:198
bool m_doNotAllowPads
Definition: zone.h:872
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: zone.cpp:1342
VECTOR2I B
Definition: seg.h:50