KiCad PCB EDA Suite
zone_filler.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) 2014-2017 CERN
5  * Copyright (C) 2014-2019 KiCad Developers, see AUTHORS.txt for contributors.
6  * @author Tomasz W┼éostowski <tomasz.wlostowski@cern.ch>
7  *
8  * This program is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation, either version 3 of the License, or (at your
11  * 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 <cstdint>
27 #include <thread>
28 #include <mutex>
29 #include <algorithm>
30 #include <future>
31 
32 #include <class_board.h>
33 #include <class_zone.h>
34 #include <class_module.h>
35 #include <class_edge_mod.h>
36 #include <class_drawsegment.h>
37 #include <class_track.h>
38 #include <class_pcb_text.h>
39 #include <class_pcb_target.h>
40 
42 #include <board_commit.h>
43 
45 
47 #include <geometry/shape_file_io.h>
48 #include <geometry/convex_hull.h>
50 #include <confirm.h>
51 #include <convert_to_biu.h>
52 
53 #include "zone_filler.h"
54 
55 #include <advanced_config.h> // To be removed later, when the zone fill option will be always allowed
56 
58 {
59 public:
61  {
62  m_reporter = aReporter;
63 
64  if( aReporter )
65  aReporter->Hide();
66  }
67 
69  {
70  if( m_reporter )
71  m_reporter->Show();
72  }
73 
74 private:
76 };
77 
78 
79 static const double s_RoundPadThermalSpokeAngle = 450;
80 static const bool s_DumpZonesWhenFilling = false;
81 
82 
83 ZONE_FILLER::ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit ) :
84  m_board( aBoard ), m_brdOutlinesValid( false ), m_commit( aCommit ),
85  m_progressReporter( nullptr )
86 {
87 }
88 
89 
91 {
92 }
93 
94 
95 void ZONE_FILLER::InstallNewProgressReporter( wxWindow* aParent, const wxString& aTitle,
96  int aNumPhases )
97 {
98  m_uniqueReporter = std::make_unique<WX_PROGRESS_REPORTER>( aParent, aTitle, aNumPhases );
100 }
101 
102 
103 bool ZONE_FILLER::Fill( const std::vector<ZONE_CONTAINER*>& aZones, bool aCheck )
104 {
105  std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> toFill;
106  auto connectivity = m_board->GetConnectivity();
107  bool filledPolyWithOutline = not m_board->GetDesignSettings().m_ZoneUseNoOutlineInFill;
108 
109  std::unique_lock<std::mutex> lock( connectivity->GetLock(), std::try_to_lock );
110 
111  if( !lock )
112  return false;
113 
114  if( m_progressReporter )
115  {
116  m_progressReporter->Report( aCheck ? _( "Checking zone fills..." ) : _( "Building zone fills..." ) );
117  m_progressReporter->SetMaxProgress( toFill.size() );
118  }
119 
120  // The board outlines is used to clip solid areas inside the board (when outlines are valid)
123 
124  for( auto zone : aZones )
125  {
126  // Keepout zones are not filled
127  if( zone->GetIsKeepout() )
128  continue;
129 
130  if( m_commit )
131  m_commit->Modify( zone );
132 
133  // calculate the hash value for filled areas. it will be used later
134  // to know if the current filled areas are up to date
135  zone->BuildHashValue();
136 
137  // Add the zone to the list of zones to test or refill
138  toFill.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST(zone) );
139 
140  // Remove existing fill first to prevent drawing invalid polygons
141  // on some platforms
142  zone->UnFill();
143  }
144 
145  std::atomic<size_t> nextItem( 0 );
146  size_t parallelThreadCount =
147  std::min<size_t>( std::thread::hardware_concurrency(), aZones.size() );
148  std::vector<std::future<size_t>> returns( parallelThreadCount );
149 
150  auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
151  {
152  size_t num = 0;
153 
154  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
155  {
156  ZONE_CONTAINER* zone = toFill[i].m_zone;
157  zone->SetFilledPolysUseThickness( filledPolyWithOutline );
158  SHAPE_POLY_SET rawPolys, finalPolys;
159  fillSingleZone( zone, rawPolys, finalPolys );
160 
161  zone->SetRawPolysList( rawPolys );
162  zone->SetFilledPolysList( finalPolys );
163  zone->SetIsFilled( true );
164 
165  if( m_progressReporter )
167 
168  num++;
169  }
170 
171  return num;
172  };
173 
174  if( parallelThreadCount <= 1 )
175  fill_lambda( m_progressReporter );
176  else
177  {
178  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
179  returns[ii] = std::async( std::launch::async, fill_lambda, m_progressReporter );
180 
181  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
182  {
183  // Here we balance returns with a 100ms timeout to allow UI updating
184  std::future_status status;
185  do
186  {
187  if( m_progressReporter )
189 
190  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
191  } while( status != std::future_status::ready );
192  }
193  }
194 
195  // Now update the connectivity to check for copper islands
196  if( m_progressReporter )
197  {
199  m_progressReporter->Report( _( "Removing insulated copper islands..." ) );
201  }
202 
203  connectivity->SetProgressReporter( m_progressReporter );
204  connectivity->FindIsolatedCopperIslands( toFill );
205 
206  // Now remove insulated copper islands and islands outside the board edge
207  bool outOfDate = false;
208 
209  for( auto& zone : toFill )
210  {
211  std::sort( zone.m_islands.begin(), zone.m_islands.end(), std::greater<int>() );
212  SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList();
213 
214  // Remove solid areas outside the board cutouts and the insulated islands
215  // only zones with net code > 0 can have insulated islands by definition
216  if( zone.m_zone->GetNetCode() > 0 )
217  {
218  // solid areas outside the board cutouts are also removed, because they are usually
219  // insulated islands
220  for( auto idx : zone.m_islands )
221  {
222  poly.DeletePolygon( idx );
223  }
224  }
225  // Zones with no net can have areas outside the board cutouts.
226  // By definition, Zones with no net have no isolated island
227  // (in fact all filled areas are isolated islands)
228  // but they can have some areas outside the board cutouts.
229  // A filled area outside the board cutouts has all points outside cutouts,
230  // so we only need to check one point for each filled polygon.
231  // Note also non copper zones are already clipped
232  else if( m_brdOutlinesValid && zone.m_zone->IsOnCopperLayer() )
233  {
234  for( int idx = 0; idx < poly.OutlineCount(); )
235  {
236  if( poly.Polygon( idx ).empty() ||
237  !m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
238  {
239  poly.DeletePolygon( idx );
240  }
241  else
242  idx++;
243  }
244  }
245 
246  zone.m_zone->SetFilledPolysList( poly );
247 
248  if( aCheck && zone.m_zone->GetHashValue() != poly.GetHash() )
249  outOfDate = true;
250  }
251 
252  if( aCheck && outOfDate )
253  {
255  KIDIALOG dlg( m_progressReporter->GetParent(),
256  _( "Zone fills are out-of-date. Refill?" ),
257  _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
258  dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) );
259  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
260 
261  if( dlg.ShowModal() == wxID_CANCEL )
262  {
263  if( m_commit )
264  m_commit->Revert();
265 
266  connectivity->SetProgressReporter( nullptr );
267  return false;
268  }
269  }
270 
271  if( m_progressReporter )
272  {
274  m_progressReporter->Report( _( "Performing polygon fills..." ) );
275  m_progressReporter->SetMaxProgress( toFill.size() );
276  }
277 
278 
279  nextItem = 0;
280 
281  auto tri_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
282  {
283  size_t num = 0;
284 
285  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
286  {
287  toFill[i].m_zone->CacheTriangulation();
288  num++;
289 
290  if( m_progressReporter )
292  }
293 
294  return num;
295  };
296 
297  if( parallelThreadCount <= 1 )
298  tri_lambda( m_progressReporter );
299  else
300  {
301  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
302  returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter );
303 
304  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
305  {
306  // Here we balance returns with a 100ms timeout to allow UI updating
307  std::future_status status;
308  do
309  {
310  if( m_progressReporter )
312 
313  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
314  } while( status != std::future_status::ready );
315  }
316  }
317 
318  if( m_progressReporter )
319  {
321  m_progressReporter->Report( _( "Committing changes..." ) );
323  }
324 
325  connectivity->SetProgressReporter( nullptr );
326 
327  if( m_commit )
328  {
329  m_commit->Push( _( "Fill Zone(s)" ), false );
330  }
331  else
332  {
333  for( auto& i : toFill )
334  connectivity->Update( i.m_zone );
335 
336  connectivity->RecalculateRatsnest();
337  }
338 
339  return true;
340 }
341 
342 
346 bool hasThermalConnection( D_PAD* pad, const ZONE_CONTAINER* aZone )
347 {
348  // Rejects non-standard pads with tht-only thermal reliefs
349  if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
350  && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
351  {
352  return false;
353  }
354 
355  if( aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
356  && aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
357  {
358  return false;
359  }
360 
361  if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0 )
362  return false;
363 
364  EDA_RECT item_boundingbox = pad->GetBoundingBox();
365  int thermalGap = aZone->GetThermalReliefGap( pad );
366  item_boundingbox.Inflate( thermalGap, thermalGap );
367 
368  return item_boundingbox.Intersects( aZone->GetBoundingBox() );
369 }
370 
371 
376 static void setupDummyPadForHole( const D_PAD* aPad, D_PAD& aDummyPad )
377 {
378  aDummyPad.SetNetCode( aPad->GetNetCode() );
379  aDummyPad.SetSize( aPad->GetDrillSize() );
380  aDummyPad.SetOrientation( aPad->GetOrientation() );
382  : PAD_SHAPE_CIRCLE );
383  aDummyPad.SetPosition( aPad->GetPosition() );
384 }
385 
386 
391 void ZONE_FILLER::addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
392 {
393  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
394  {
395  // the pad shape in zone can be its convex hull or the shape itself
396  SHAPE_POLY_SET outline( aPad->GetCustomShapeAsPolygon() );
397  int numSegs = std::max( GetArcToSegmentCount( aGap, m_high_def, 360.0 ), 6 );
398  double correction = GetCircletoPolyCorrectionFactor( numSegs );
399  outline.Inflate( KiROUND( aGap * correction ), numSegs );
400  aPad->CustomShapeAsPolygonToBoardPosition( &outline, aPad->GetPosition(),
401  aPad->GetOrientation() );
402 
404  {
405  std::vector<wxPoint> convex_hull;
406  BuildConvexHull( convex_hull, outline );
407 
408  aHoles.NewOutline();
409 
410  for( const wxPoint& pt : convex_hull )
411  aHoles.Append( pt );
412  }
413  else
414  aHoles.Append( outline );
415  }
416  else
417  {
418  // Optimizing polygon vertex count: the high definition is used for round
419  // and oval pads (pads with large arcs) but low def for other shapes (with
420  // small arcs)
421  if( aPad->GetShape() == PAD_SHAPE_CIRCLE || aPad->GetShape() == PAD_SHAPE_OVAL ||
422  ( aPad->GetShape() == PAD_SHAPE_ROUNDRECT && aPad->GetRoundRectRadiusRatio() > 0.4 ) )
423  aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def );
424  else
425  aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_low_def );
426  }
427 }
428 
429 
434 void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidth,
435  SHAPE_POLY_SET& aHoles )
436 {
437  switch( aItem->Type() )
438  {
439  case PCB_LINE_T:
440  {
441  DRAWSEGMENT* seg = (DRAWSEGMENT*) aItem;
442  seg->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth );
443  break;
444  }
445  case PCB_TEXT_T:
446  {
447  TEXTE_PCB* text = (TEXTE_PCB*) aItem;
448  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
449  break;
450  }
451  case PCB_MODULE_EDGE_T:
452  {
453  EDGE_MODULE* edge = (EDGE_MODULE*) aItem;
454  edge->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth );
455  break;
456  }
457  case PCB_MODULE_TEXT_T:
458  {
459  TEXTE_MODULE* text = (TEXTE_MODULE*) aItem;
460 
461  if( text->IsVisible() )
462  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
463 
464  break;
465  }
466  default:
467  break;
468  }
469 }
470 
471 
477 {
478  SHAPE_POLY_SET holes;
479 
480  // Use a dummy pad to calculate relief when a pad has a hole but is not on the zone's
481  // copper layer. The dummy pad has the size and shape of the original pad's hole. We have
482  // to give it a parent because some functions expect a non-null parent to find clearance
483  // data, etc.
484  MODULE dummymodule( m_board );
485  D_PAD dummypad( &dummymodule );
486 
487  for( auto module : m_board->Modules() )
488  {
489  for( auto pad : module->Pads() )
490  {
491  if( !hasThermalConnection( pad, aZone ) )
492  continue;
493 
494  // If the pad isn't on the current layer but has a hole, knock out a thermal relief
495  // for the hole.
496  if( !pad->IsOnLayer( aZone->GetLayer() ) )
497  {
498  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
499  continue;
500 
501  setupDummyPadForHole( pad, dummypad );
502  pad = &dummypad;
503  }
504 
505  addKnockout( pad, aZone->GetThermalReliefGap( pad ), holes );
506  }
507  }
508 
511 }
512 
513 
519 {
520  int zone_clearance = aZone->GetClearance();
521  int edgeClearance = m_board->GetDesignSettings().m_CopperEdgeClearance;
522  int zone_to_edgecut_clearance = std::max( aZone->GetZoneClearance(), edgeClearance );
523 
524  // items outside the zone bounding box are skipped
525  // the bounding box is the zone bounding box + the biggest clearance found in Netclass list
526  EDA_RECT zone_boundingbox = aZone->GetBoundingBox();
527  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
528  biggest_clearance = std::max( biggest_clearance, zone_clearance );
529  zone_boundingbox.Inflate( biggest_clearance );
530 
531  // Use a dummy pad to calculate hole clearance when a pad has a hole but is not on the
532  // zone's copper layer. The dummy pad has the size and shape of the original pad's hole.
533  // We have to give it a parent because some functions expect a non-null parent to find
534  // clearance data, etc.
535  MODULE dummymodule( m_board );
536  D_PAD dummypad( &dummymodule );
537 
538  // Add non-connected pad clearances
539  //
540  for( auto module : m_board->Modules() )
541  {
542  for( auto pad : module->Pads() )
543  {
544  if( !pad->IsOnLayer( aZone->GetLayer() ) )
545  {
546  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
547  continue;
548 
549  setupDummyPadForHole( pad, dummypad );
550  pad = &dummypad;
551  }
552 
553  if( pad->GetNetCode() != aZone->GetNetCode()
554  || pad->GetNetCode() <= 0
555  || aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_NONE )
556  {
557  int gap = std::max( zone_clearance, pad->GetClearance() );
558  EDA_RECT item_boundingbox = pad->GetBoundingBox();
559  item_boundingbox.Inflate( pad->GetClearance() );
560 
561  if( item_boundingbox.Intersects( zone_boundingbox ) )
562  addKnockout( pad, gap, aHoles );
563  }
564  }
565  }
566 
567  // Add non-connected track clearances
568  //
569  for( auto track : m_board->Tracks() )
570  {
571  if( !track->IsOnLayer( aZone->GetLayer() ) )
572  continue;
573 
574  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
575  continue;
576 
577  int gap = std::max( zone_clearance, track->GetClearance() );
578  EDA_RECT item_boundingbox = track->GetBoundingBox();
579 
580  if( item_boundingbox.Intersects( zone_boundingbox ) )
581  track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def );
582  }
583 
584  // Add graphic item clearances. They are by definition unconnected, and have no clearance
585  // definitions of their own.
586  //
587  auto doGraphicItem = [&]( BOARD_ITEM* aItem )
588  {
589  // A item on the Edge_Cuts is always seen as on any layer:
590  if( !aItem->IsOnLayer( aZone->GetLayer() ) && !aItem->IsOnLayer( Edge_Cuts ) )
591  return;
592 
593  if( !aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
594  return;
595 
596  bool ignoreLineWidth = false;
597  int gap = zone_clearance;
598 
599  if( aItem->IsOnLayer( Edge_Cuts ) )
600  {
601  gap = zone_to_edgecut_clearance;
602 
603  // edge cuts by definition don't have a width
604  ignoreLineWidth = true;
605  }
606 
607  addKnockout( aItem, gap, ignoreLineWidth, aHoles );
608  };
609 
610  for( auto module : m_board->Modules() )
611  {
612  doGraphicItem( &module->Reference() );
613  doGraphicItem( &module->Value() );
614 
615  for( auto item : module->GraphicalItems() )
616  doGraphicItem( item );
617  }
618 
619  for( auto item : m_board->Drawings() )
620  doGraphicItem( item );
621 
622  // Add zones outlines having an higher priority and keepout
623  //
624  for( ZONE_CONTAINER* zone : m_board->GetZoneList( true ) )
625  {
626 
627  // If the zones share no common layers
628  if( !aZone->CommonLayerExists( zone->GetLayerSet() ) )
629  continue;
630 
631  if( !zone->GetIsKeepout() && zone->GetPriority() <= aZone->GetPriority() )
632  continue;
633 
634  if( zone->GetIsKeepout() && !zone->GetDoNotAllowCopperPour() )
635  continue;
636 
637  // A higher priority zone or keepout area is found: remove this area
638  EDA_RECT item_boundingbox = zone->GetBoundingBox();
639 
640  if( !item_boundingbox.Intersects( zone_boundingbox ) )
641  continue;
642 
643  // Add the zone outline area. Don't use any clearance for keepouts, or for zones with
644  // the same net (they will be connected but will honor their own clearance, thermal
645  // connections, etc.).
646  bool sameNet = aZone->GetNetCode() == zone->GetNetCode();
647  bool useNetClearance = true;
648  int minClearance = zone_clearance;
649 
650  // The final clearance is obviously the max value of each zone clearance
651  minClearance = std::max( minClearance, zone->GetClearance() );
652 
653  if( zone->GetIsKeepout() || sameNet )
654  {
655  minClearance = 0;
656  useNetClearance = false;
657  }
658 
659  zone->TransformOutlinesShapeWithClearanceToPolygon( aHoles, minClearance, useNetClearance );
660  }
661 
663 }
664 
665 
678  const SHAPE_POLY_SET& aSmoothedOutline,
679  std::set<VECTOR2I>* aPreserveCorners,
680  SHAPE_POLY_SET& aRawPolys,
681  SHAPE_POLY_SET& aFinalPolys )
682 {
684  m_low_def = std::min( ARC_LOW_DEF, int( m_high_def*1.5 ) ); // Reasonable value
685 
686  // Features which are min_width should survive pruning; features that are *less* than
687  // min_width should not. Therefore we subtract epsilon from the min_width when
688  // deflating/inflating.
689  int half_min_width = aZone->GetMinThickness() / 2;
690  int epsilon = Millimeter2iu( 0.001 );
691  int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 );
692 
694 
696  cornerStrategy = SHAPE_POLY_SET::ROUND_ACUTE_CORNERS;
697 
698  std::deque<SHAPE_LINE_CHAIN> thermalSpokes;
699  SHAPE_POLY_SET clearanceHoles;
700 
701  std::unique_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO(
702  s_DumpZonesWhenFilling ? "zones_dump.txt" : "", SHAPE_FILE_IO::IOM_APPEND ) );
703 
704  aRawPolys = aSmoothedOutline;
705 
707  dumper->BeginGroup( "clipper-zone" );
708 
709  knockoutThermalReliefs( aZone, aRawPolys );
710 
712  dumper->Write( &aRawPolys, "solid-areas-minus-thermal-reliefs" );
713 
714  buildCopperItemClearances( aZone, clearanceHoles );
715 
717  dumper->Write( &aRawPolys, "clearance holes" );
718 
719  buildThermalSpokes( aZone, thermalSpokes );
720 
721  // Create a temporary zone that we can hit-test spoke-ends against. It's only temporary
722  // because the "real" subtract-clearance-holes has to be done after the spokes are added.
723  static const bool USE_BBOX_CACHES = true;
724  SHAPE_POLY_SET testAreas = aRawPolys;
725  testAreas.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
726 
727  // Prune features that don't meet minimum-width criteria
728  if( half_min_width - epsilon > epsilon )
729  {
730  testAreas.Deflate( half_min_width - epsilon, numSegs, cornerStrategy );
731  testAreas.Inflate( half_min_width - epsilon, numSegs, cornerStrategy );
732  }
733 
734  // Spoke-end-testing is hugely expensive so we generate cached bounding-boxes to speed
735  // things up a bit.
736  testAreas.BuildBBoxCaches();
737 
738  for( const SHAPE_LINE_CHAIN& spoke : thermalSpokes )
739  {
740  const VECTOR2I& testPt = spoke.CPoint( 3 );
741 
742  // Hit-test against zone body
743  if( testAreas.Contains( testPt, -1, 1, USE_BBOX_CACHES ) )
744  {
745  aRawPolys.AddOutline( spoke );
746  continue;
747  }
748 
749  // Hit-test against other spokes
750  for( const SHAPE_LINE_CHAIN& other : thermalSpokes )
751  {
752  if( &other != &spoke && other.PointInside( testPt, 1, USE_BBOX_CACHES ) )
753  {
754  aRawPolys.AddOutline( spoke );
755  break;
756  }
757  }
758  }
759 
760  // Ensure previous changes (adding thermal stubs) do not add
761  // filled areas outside the zone boundary
762  aRawPolys.BooleanIntersection( aSmoothedOutline, SHAPE_POLY_SET::PM_FAST );
763  aRawPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
764 
766  dumper->Write( &aRawPolys, "solid-areas-with-thermal-spokes" );
767 
768  aRawPolys.BooleanSubtract( clearanceHoles, SHAPE_POLY_SET::PM_FAST );
769  // Prune features that don't meet minimum-width criteria
770  if( half_min_width - epsilon > epsilon )
771  aRawPolys.Deflate( half_min_width - epsilon, numSegs, cornerStrategy );
772 
774  dumper->Write( &aRawPolys, "solid-areas-before-hatching" );
775 
776  // Now remove the non filled areas due to the hatch pattern
777  if( aZone->GetFillMode() == ZFM_HATCH_PATTERN )
778  addHatchFillTypeOnZone( aZone, aRawPolys );
779 
781  dumper->Write( &aRawPolys, "solid-areas-after-hatching" );
782 
783  // Re-inflate after pruning of areas that don't meet minimum-width criteria
784  if( aZone->GetFilledPolysUseThickness() )
785  {
786  // If we're stroking the zone with a min_width stroke then this will naturally
787  // inflate the zone by half_min_width
788  }
789  else if( half_min_width - epsilon > epsilon )
790  {
791  aRawPolys.Simplify( SHAPE_POLY_SET::PM_FAST );
792  aRawPolys.Inflate( half_min_width - epsilon, numSegs, cornerStrategy );
793 
794  // If we've deflated/inflated by something near our corner radius then we will have
795  // ended up with too-sharp corners. Apply outline smoothing again.
796  if( aZone->GetMinThickness() > (int)aZone->GetCornerRadius() )
797  aRawPolys.BooleanIntersection( aSmoothedOutline, SHAPE_POLY_SET::PM_FAST );
798  }
799 
800  aRawPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
801 
803  dumper->Write( &aRawPolys, "areas_fractured" );
804 
805  aFinalPolys = aRawPolys;
806 
808  dumper->EndGroup();
809 }
810 
811 
812 /*
813  * Build the filled solid areas data from real outlines (stored in m_Poly)
814  * The solid areas can be more than one on copper layers, and do not have holes
815  * ( holes are linked by overlapping segments to the main outline)
816  */
818  SHAPE_POLY_SET& aFinalPolys )
819 {
820  SHAPE_POLY_SET smoothedPoly;
821  std::set<VECTOR2I> colinearCorners;
822  aZone->GetColinearCorners( m_board, colinearCorners );
823 
824  /*
825  * convert outlines + holes to outlines without holes (adding extra segments if necessary)
826  * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
827  * this zone
828  */
829  if ( !aZone->BuildSmoothedPoly( smoothedPoly, &colinearCorners ) )
830  return false;
831 
832  if( aZone->IsOnCopperLayer() )
833  {
834  computeRawFilledArea( aZone, smoothedPoly, &colinearCorners, aRawPolys, aFinalPolys );
835  }
836  else
837  {
838  // Features which are min_width should survive pruning; features that are *less* than
839  // min_width should not. Therefore we subtract epsilon from the min_width when
840  // deflating/inflating.
841  int half_min_width = aZone->GetMinThickness() / 2;
842  int epsilon = Millimeter2iu( 0.001 );
843  int numSegs = std::max( GetArcToSegmentCount( half_min_width, m_high_def, 360.0 ), 6 );
844 
845  if( m_brdOutlinesValid )
847 
848  smoothedPoly.Deflate( half_min_width - epsilon, numSegs );
849 
850  // Remove the non filled areas due to the hatch pattern
851  if( aZone->GetFillMode() == ZFM_HATCH_PATTERN )
852  addHatchFillTypeOnZone( aZone, smoothedPoly );
853 
854  // Re-inflate after pruning of areas that don't meet minimum-width criteria
855  if( aZone->GetFilledPolysUseThickness() )
856  {
857  // If we're stroking the zone with a min_width stroke then this will naturally
858  // inflate the zone by half_min_width
859  }
860  else if( half_min_width - epsilon > epsilon )
861  smoothedPoly.Deflate( -( half_min_width - epsilon ), numSegs );
862 
863  aRawPolys = smoothedPoly;
864  aFinalPolys = smoothedPoly;
865 
867  }
868 
869  aZone->SetNeedRefill( false );
870  return true;
871 }
872 
873 
878  std::deque<SHAPE_LINE_CHAIN>& aSpokesList )
879 {
880  auto zoneBB = aZone->GetBoundingBox();
881  int zone_clearance = aZone->GetZoneClearance();
882  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
883  biggest_clearance = std::max( biggest_clearance, zone_clearance );
884  zoneBB.Inflate( biggest_clearance );
885 
886  // Is a point on the boundary of the polygon inside or outside? This small epsilon lets
887  // us avoid the question.
888  int epsilon = KiROUND( IU_PER_MM * 0.04 ); // about 1.5 mil
889 
890  for( auto module : m_board->Modules() )
891  {
892  for( auto pad : module->Pads() )
893  {
894  if( !hasThermalConnection( pad, aZone ) )
895  continue;
896 
897  // We currently only connect to pads, not pad holes
898  if( !pad->IsOnLayer( aZone->GetLayer() ) )
899  continue;
900 
901  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
902 
903  // Calculate thermal bridge half width
904  int spoke_w = aZone->GetThermalReliefCopperBridge( pad );
905  // Avoid spoke_w bigger than the smaller pad size, because
906  // it is not possible to create stubs bigger than the pad.
907  // Possible refinement: have a separate size for vertical and horizontal stubs
908  spoke_w = std::min( spoke_w, pad->GetSize().x );
909  spoke_w = std::min( spoke_w, pad->GetSize().y );
910 
911  // Cannot create stubs having a width < zone min thickness
912  if( spoke_w <= aZone->GetMinThickness() )
913  continue;
914 
915  int spoke_half_w = spoke_w / 2;
916 
917  // Quick test here to possibly save us some work
918  BOX2I itemBB = pad->GetBoundingBox();
919  itemBB.Inflate( thermalReliefGap + epsilon );
920 
921  if( !( itemBB.Intersects( zoneBB ) ) )
922  continue;
923 
924  // Thermal spokes consist of segments from the pad center to points just outside
925  // the thermal relief.
926  //
927  // We use the bounding-box to lay out the spokes, but for this to work the
928  // bounding box has to be built at the same rotation as the spokes.
929 
930  wxPoint shapePos = pad->ShapePos();
931  wxPoint padPos = pad->GetPosition();
932  double padAngle = pad->GetOrientation();
933  pad->SetOrientation( 0.0 );
934  pad->SetPosition( { 0, 0 } );
935  BOX2I reliefBB = pad->GetBoundingBox();
936  pad->SetPosition( padPos );
937  pad->SetOrientation( padAngle );
938 
939  reliefBB.Inflate( thermalReliefGap + epsilon );
940 
941  // For circle pads, the thermal spoke orientation is 45 deg
942  if( pad->GetShape() == PAD_SHAPE_CIRCLE )
943  padAngle = s_RoundPadThermalSpokeAngle;
944 
945  for( int i = 0; i < 4; i++ )
946  {
947  SHAPE_LINE_CHAIN spoke;
948  switch( i )
949  {
950  case 0: // lower stub
951  spoke.Append( +spoke_half_w, -spoke_half_w );
952  spoke.Append( -spoke_half_w, -spoke_half_w );
953  spoke.Append( -spoke_half_w, reliefBB.GetBottom() );
954  spoke.Append( 0, reliefBB.GetBottom() ); // test pt
955  spoke.Append( +spoke_half_w, reliefBB.GetBottom() );
956  break;
957 
958  case 1: // upper stub
959  spoke.Append( +spoke_half_w, spoke_half_w );
960  spoke.Append( -spoke_half_w, spoke_half_w );
961  spoke.Append( -spoke_half_w, reliefBB.GetTop() );
962  spoke.Append( 0, reliefBB.GetTop() ); // test pt
963  spoke.Append( +spoke_half_w, reliefBB.GetTop() );
964  break;
965 
966  case 2: // right stub
967  spoke.Append( -spoke_half_w, spoke_half_w );
968  spoke.Append( -spoke_half_w, -spoke_half_w );
969  spoke.Append( reliefBB.GetRight(), -spoke_half_w );
970  spoke.Append( reliefBB.GetRight(), 0 ); // test pt
971  spoke.Append( reliefBB.GetRight(), spoke_half_w );
972  break;
973 
974  case 3: // left stub
975  spoke.Append( spoke_half_w, spoke_half_w );
976  spoke.Append( spoke_half_w, -spoke_half_w );
977  spoke.Append( reliefBB.GetLeft(), -spoke_half_w );
978  spoke.Append( reliefBB.GetLeft(), 0 ); // test pt
979  spoke.Append( reliefBB.GetLeft(), spoke_half_w );
980  break;
981  }
982 
983  spoke.Rotate( -DECIDEG2RAD( padAngle ) );
984  spoke.Move( shapePos );
985 
986  spoke.SetClosed( true );
987  spoke.GenerateBBoxCache();
988  aSpokesList.push_back( std::move( spoke ) );
989  }
990  }
991  }
992 }
993 
994 
996 {
997  // Build grid:
998 
999  // obviously line thickness must be > zone min thickness.
1000  // It can happens if a board file was edited by hand by a python script
1001  // Use 1 micron margin to be *sure* there is no issue in Gerber files
1002  // (Gbr file unit = 1 or 10 nm) due to some truncation in coordinates or calculations
1003  // This margin also avoid problems due to rounding coordinates in next calculations
1004  // that can create incorrect polygons
1005  int thickness = std::max( aZone->GetHatchFillTypeThickness(),
1006  aZone->GetMinThickness()+Millimeter2iu( 0.001 ) );
1007 
1008  int linethickness = thickness - aZone->GetMinThickness();
1009  int gridsize = thickness + aZone->GetHatchFillTypeGap();
1010  double orientation = aZone->GetHatchFillTypeOrientation();
1011 
1012  SHAPE_POLY_SET filledPolys = aRawPolys;
1013  // Use a area that contains the rotated bbox by orientation,
1014  // and after rotate the result by -orientation.
1015  if( orientation != 0.0 )
1016  {
1017  filledPolys.Rotate( M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1018  }
1019 
1020  BOX2I bbox = filledPolys.BBox( 0 );
1021 
1022  // Build hole shape
1023  // the hole size is aZone->GetHatchFillTypeGap(), but because the outline thickness
1024  // is aZone->GetMinThickness(), the hole shape size must be larger
1025  SHAPE_LINE_CHAIN hole_base;
1026  int hole_size = aZone->GetHatchFillTypeGap() + aZone->GetMinThickness();
1027  VECTOR2I corner( 0, 0 );;
1028  hole_base.Append( corner );
1029  corner.x += hole_size;
1030  hole_base.Append( corner );
1031  corner.y += hole_size;
1032  hole_base.Append( corner );
1033  corner.x = 0;
1034  hole_base.Append( corner );
1035  hole_base.SetClosed( true );
1036 
1037  // Calculate minimal area of a grid hole.
1038  // All holes smaller than a threshold will be removed
1039  double minimal_hole_area = hole_base.Area() / 2;
1040 
1041  // Now convert this hole to a smoothed shape:
1042  if( aZone->GetHatchFillTypeSmoothingLevel() > 0 )
1043  {
1044  // the actual size of chamfer, or rounded corner radius is the half size
1045  // of the HatchFillTypeGap scaled by aZone->GetHatchFillTypeSmoothingValue()
1046  // aZone->GetHatchFillTypeSmoothingValue() = 1.0 is the max value for the chamfer or the
1047  // radius of corner (radius = half size of the hole)
1048  int smooth_value = KiROUND( aZone->GetHatchFillTypeGap()
1049  * aZone->GetHatchFillTypeSmoothingValue() / 2 );
1050 
1051  // Minimal optimization:
1052  // make smoothing only for reasonnable smooth values, to avoid a lot of useless segments
1053  // and if the smooth value is small, use chamfer even if fillet is requested
1054  #define SMOOTH_MIN_VAL_MM 0.02
1055  #define SMOOTH_SMALL_VAL_MM 0.04
1056  if( smooth_value > Millimeter2iu( SMOOTH_MIN_VAL_MM ) )
1057  {
1058  SHAPE_POLY_SET smooth_hole;
1059  smooth_hole.AddOutline( hole_base );
1060  int smooth_level = aZone->GetHatchFillTypeSmoothingLevel();
1061 
1062  if( smooth_value < Millimeter2iu( SMOOTH_SMALL_VAL_MM ) && smooth_level > 1 )
1063  smooth_level = 1;
1064  // Use a larger smooth_value to compensate the outline tickness
1065  // (chamfer is not visible is smooth value < outline thickess)
1066  smooth_value += aZone->GetMinThickness()/2;
1067 
1068  // smooth_value cannot be bigger than the half size oh the hole:
1069  smooth_value = std::min( smooth_value, aZone->GetHatchFillTypeGap()/2 );
1070  // the error to approximate a circle by segments when smoothing corners by a arc
1071  int error_max = std::max( Millimeter2iu( 0.01), smooth_value/20 );
1072 
1073  switch( smooth_level )
1074  {
1075  case 1:
1076  // Chamfer() uses the distance from a corner to create a end point
1077  // for the chamfer.
1078  hole_base = smooth_hole.Chamfer( smooth_value ).Outline( 0 );
1079  break;
1080 
1081  default:
1082  if( aZone->GetHatchFillTypeSmoothingLevel() > 2 )
1083  error_max /= 2; // Force better smoothing
1084  hole_base = smooth_hole.Fillet( smooth_value, error_max ).Outline( 0 );
1085  break;
1086 
1087  case 0:
1088  break;
1089  };
1090  }
1091  }
1092 
1093  // Build holes
1094  SHAPE_POLY_SET holes;
1095 
1096  for( int xx = 0; ; xx++ )
1097  {
1098  int xpos = xx * gridsize;
1099 
1100  if( xpos > bbox.GetWidth() )
1101  break;
1102 
1103  for( int yy = 0; ; yy++ )
1104  {
1105  int ypos = yy * gridsize;
1106 
1107  if( ypos > bbox.GetHeight() )
1108  break;
1109 
1110  // Generate hole
1111  SHAPE_LINE_CHAIN hole( hole_base );
1112  hole.Move( VECTOR2I( xpos, ypos ) );
1113  holes.AddOutline( hole );
1114  }
1115  }
1116 
1117  holes.Move( bbox.GetPosition() );
1118 
1119  // Clamp holes to the area of filled zones with a outline thickness
1120  // > aZone->GetMinThickness() to be sure the thermal pads can be built
1121  int outline_margin = std::max( (aZone->GetMinThickness()*10)/9, linethickness/2 );
1122  filledPolys.Deflate( outline_margin, 16 );
1123  holes.BooleanIntersection( filledPolys, SHAPE_POLY_SET::PM_FAST );
1124 
1125  if( orientation != 0.0 )
1126  holes.Rotate( -M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1127 
1128  // Now filter truncated holes to avoid small holes in pattern
1129  // It happens for holes near the zone outline
1130  for( int ii = 0; ii < holes.OutlineCount(); )
1131  {
1132  double area = holes.Outline( ii ).Area();
1133 
1134  if( area < minimal_hole_area ) // The current hole is too small: remove it
1135  holes.DeletePolygon( ii );
1136  else
1137  ++ii;
1138  }
1139 
1140  // create grid. Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to
1141  // generate strictly simple polygons needed by Gerber files and Fracture()
1142  aRawPolys.BooleanSubtract( aRawPolys, holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1143 }
void SetFilledPolysList(SHAPE_POLY_SET &aPolysList)
Function SetFilledPolysList sets the list of filled polygons.
Definition: class_zone.h:566
virtual void Revert()=0
Revertes the commit by restoring the modifed items state.
void AdvancePhase()
Uses the next vailable virtual zone of the dialog progress bar.
void Rotate(double aAngle, const VECTOR2I &aCenter={ 0, 0 })
Function Rotate rotates all vertices by a given angle.
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:60
COMMIT & Modify(EDA_ITEM *aItem)
Modifies a given item in the model.
Definition: commit.h:103
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox
Definition: confirm.cpp:53
Class SHAPE_FILE_IO.
Definition: shape_file_io.h:39
int GetNetCode() const
Function GetNetCode.
int OutlineCount() const
Returns the number of outlines in the set
TEXTE_PCB class definition.
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)
bool CommonLayerExists(const LSET aLayerSet) const
Function CommonLayerExist Test if this zone shares a common layer with the given layer set.
Definition: class_zone.cpp:222
int GetThermalReliefCopperBridge(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:532
void SetFilledPolysUseThickness(bool aOption)
Definition: class_zone.h:599
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: confirm.h:44
This file is part of the common library.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
BOARD * m_board
Definition: zone_filler.h:106
coord_type GetTop() const
Definition: box2.h:202
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox (virtual)
Definition: class_zone.cpp:496
int GetBiggestClearanceValue()
Function GetBiggestClearanceValue.
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the draw segment to a closed polygon Used in fi...
void Rotate(double aAngle, const VECTOR2I &aCenter=VECTOR2I(0, 0))
Function Rotate rotates all vertices by a given angle.
PROGRESS_REPORTER_HIDER(WX_PROGRESS_REPORTER *aReporter)
Definition: zone_filler.cpp:60
A progress reporter for use in multi-threaded environments.
int GetHatchFillTypeThickness() const
Definition: class_zone.h:194
bool IsVisible() const
Definition: eda_text.h:170
void addKnockout(D_PAD *aPad, int aGap, SHAPE_POLY_SET &aHoles)
Add a knockout for a pad.
WX_PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:111
void computeRawFilledArea(const ZONE_CONTAINER *aZone, const SHAPE_POLY_SET &aSmoothedOutline, std::set< VECTOR2I > *aPreserveCorners, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys)
Function computeRawFilledArea Add non copper areas polygons (pads and tracks with clearance) to a fil...
void Move(const VECTOR2I &aVector) override
static const double s_RoundPadThermalSpokeAngle
Definition: zone_filler.cpp:79
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:203
#define SMOOTH_MIN_VAL_MM
void Report(const wxString &aMessage)
Display aMessage in the progress bar dialog.
bool GetFilledPolysUseThickness() const
Definition: class_zone.h:598
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
double GetHatchFillTypeOrientation() const
Definition: class_zone.h:200
coord_type GetRight() const
Definition: box2.h:197
void buildCopperItemClearances(const ZONE_CONTAINER *aZone, SHAPE_POLY_SET &aHoles)
Removes clearance from the shape for copper items which share the zone's layer but are not connected ...
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:240
Class COMMIT.
Definition: commit.h:71
double GetHatchFillTypeSmoothingValue() const
Definition: class_zone.h:206
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:531
std::unique_ptr< WX_PROGRESS_REPORTER > m_uniqueReporter
Definition: zone_filler.h:112
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, int aAccuracy=0, bool aUseBBoxCaches=false) const
Returns true if a given subpolygon contains the point aP.
void TransformBoundingBoxWithClearanceToPolygon(SHAPE_POLY_SET *aCornerBuffer, int aClearanceValue) const
Function TransformBoundingBoxWithClearanceToPolygon Convert the text bounding box to a rectangular po...
coord_type GetBottom() const
Definition: box2.h:198
void Inflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
Performs outline inflation/deflation.
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:523
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
#define SMOOTH_SMALL_VAL_MM
void SetIsFilled(bool isFilled)
Definition: class_zone.h:174
void BuildConvexHull(std::vector< wxPoint > &aResult, const std::vector< wxPoint > &aPoly)
Calculate the convex hull of a list of points in counter-clockwise order.
Definition: convex_hull.cpp:87
static const bool s_DumpZonesWhenFilling
Definition: zone_filler.cpp:80
class EDGE_MODULE, a footprint edge
Definition: typeinfo.h:94
int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
Definition: class_zone.cpp:649
PAD_ATTR_T GetAttribute() const
Definition: class_pad.h:445
Definitions for tracks, vias and zones.
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
void InstallNewProgressReporter(wxWindow *aParent, const wxString &aTitle, int aNumPhases)
Definition: zone_filler.cpp:95
void DeletePolygon(int aIdx)
Deletes aIdx-th polygon from the set
Pads are not covered.
Definition: zones.h:52
WX_PROGRESS_REPORTER * m_reporter
Definition: zone_filler.cpp:75
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:234
void GetColinearCorners(BOARD *aBoard, std::set< VECTOR2I > &colinearCorners)
Some intersecting zones, despite being on the same layer with the same net, cannot be merged due to o...
void SetClosed(bool aClosed)
Function SetClosed()
unsigned int GetCornerRadius() const
Definition: class_zone.h:596
void Move(const VECTOR2I &aVector) override
COMMIT * m_commit
Definition: zone_filler.h:110
MODULES & Modules()
Definition: class_board.h:227
Class SHAPE_POLY_SET.
SHAPE_LINE_CHAIN & Outline(int aIndex)
Returns the reference to aIndex-th outline in the set
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit=nullptr)
Definition: zone_filler.cpp:83
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly, std::set< VECTOR2I > *aPreserveCorners) const
Function GetSmoothedPoly returns a pointer to the corner-smoothed version of m_Poly.
ZONE_FILL_MODE GetFillMode() const
Definition: class_zone.h:159
coord_type GetWidth() const
Definition: box2.h:195
PAD_DRILL_SHAPE_T GetDrillShape() const
Definition: class_pad.h:428
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:301
void Deflate(int aAmount, int aCircleSegmentsCount, CORNER_STRATEGY aCornerStrategy=ROUND_ALL_CORNERS)
void SetSize(const wxSize &aSize)
Definition: class_pad.h:299
bool SetNetCode(int aNetCode, bool aNoAssert=false)
Sets net using a net code.
a few functions useful in geometry calculations.
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
bool GetBoardPolygonOutlines(SHAPE_POLY_SET &aOutlines, wxString *aErrorText=nullptr, wxPoint *aErrorLocation=nullptr)
Function GetBoardPolygonOutlines Extracts the board outlines and build a closed polygon from lines,...
bool Fill(const std::vector< ZONE_CONTAINER * > &aZones, bool aCheck=false)
void knockoutThermalReliefs(const ZONE_CONTAINER *aZone, SHAPE_POLY_SET &aFill)
Removes thermal reliefs from the shape for any pads connected to the zone.
void BooleanIntersection(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset intersection For aFastMode meaning, see function booleanOp
int NewOutline()
Creates a new empty polygon in the set and returns its index
#define _(s)
void addHatchFillTypeOnZone(const ZONE_CONTAINER *aZone, SHAPE_POLY_SET &aRawPolys)
for zones having the ZONE_FILL_MODE::ZFM_HATCH_PATTERN, create a grid pattern in filled areas of aZon...
int GetCornerSmoothingType() const
Definition: class_zone.h:592
Thermal relief only for THT pads.
Definition: zones.h:55
void Fracture(POLYGON_MODE aFastMode)
Converts a set of polygons with holes to a singe outline with "slits"/"fractures" connecting the oute...
void SetRawPolysList(SHAPE_POLY_SET &aPolysList)
Function SetFilledPolysList sets the list of filled polygons.
Definition: class_zone.h:575
void BuildBBoxCaches()
Constructs BBoxCaches for Contains(), below.
double Area() const
const Vec & GetPosition() const
Definition: box2.h:192
CUST_PAD_SHAPE_IN_ZONE GetCustomShapeInZoneOpt() const
Definition: class_pad.h:253
SHAPE_POLY_SET Fillet(int aRadius, int aErrorMax, std::set< VECTOR2I > *aPreserveCorners=nullptr)
Function Fillet returns a filleted version of the polygon set.
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
int AddOutline(const SHAPE_LINE_CHAIN &aOutline)
Adds a new outline to the set and returns its index
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aMaxError=ARC_HIGH_DEF, bool ignoreLineWidth=false) const override
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon Used in filli...
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:300
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true)=0
Executes the changes.
unsigned GetPriority() const
Function GetPriority.
Definition: class_zone.h:103
Class to handle a graphic segment.
ZoneConnection GetPadConnection(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:866
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:161
Class SHAPE_LINE_CHAIN.
bool m_ZoneUseNoOutlineInFill
Option to handle filled polygons in zones: the "legacy" option is using thick outlines around filled ...
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees,...
Definition: class_pad.h:422
void CustomShapeAsPolygonToBoardPosition(SHAPE_POLY_SET *aMergedPolygon, wxPoint aPosition, double aRotation) const
When created, the corners coordinates are relative to the pad position, orientation 0,...
size_t i
Definition: json11.cpp:649
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
bool KeepRefreshing(bool aWait=false)
Update the UI dialog.
const wxSize & GetDrillSize() const
Definition: class_pad.h:306
const SHAPE_POLY_SET & GetCustomShapeAsPolygon() const
Accessor to the custom shape as one polygon.
Definition: class_pad.h:374
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
double DECIDEG2RAD(double deg)
Definition: trigo.h:214
SHAPE_POLY_SET Chamfer(int aDistance, std::set< VECTOR2I > *aPreserveCorners=nullptr)
Function Chamfer returns a chamfered version of the polygon set.
coord_type GetHeight() const
Definition: box2.h:196
int GetMinThickness() const
Definition: class_zone.h:185
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:238
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
void SetOrientation(double aAngle)
Function SetOrientation sets the rotation angle of the pad.
Definition: class_pad.cpp:430
double GetRoundRectRadiusRatio() const
has meaning only for rounded rect pads
Definition: class_pad.h:660
SHAPE_POLY_SET m_boardOutline
Definition: zone_filler.h:107
int GetHatchFillTypeSmoothingLevel() const
Definition: class_zone.h:203
PCB_TARGET class definition.
bool m_brdOutlinesValid
Definition: zone_filler.h:108
static void setupDummyPadForHole(const D_PAD *aPad, D_PAD &aDummyPad)
Setup aDummyPad to have the same size and shape of aPad's hole.
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:237
Module description (excepted pads)
coord_type GetLeft() const
Definition: box2.h:201
int GetZoneClearance() const
Definition: class_zone.h:179
const wxPoint GetPosition() const override
Definition: class_pad.h:241
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
void SetMaxProgress(int aMaxProgress)
Fix the value thar gives the 100 precent progress bar length (inside the current virtual zone)
void AdvanceProgress()
Increment the progress bar length (inside the current virtual zone)
const BOX2I BBox(int aClearance=0) const override
Function BBox()
int GetHatchFillTypeGap() const
Definition: class_zone.h:197
DRAWINGS & Drawings()
Definition: class_board.h:236
Use thermal relief for pads.
Definition: zones.h:53
void buildThermalSpokes(const ZONE_CONTAINER *aZone, std::deque< SHAPE_LINE_CHAIN > &aSpokes)
Function buildThermalSpokes Constructs a list of all thermal spokes for the given zone.
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: class_pad.cpp:227
TRACKS & Tracks()
Definition: class_board.h:218
bool IsOnCopperLayer() const override
Function IsOnCopperLayer.
Definition: class_zone.cpp:209
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
KICAD_T Type() const
Function Type()
Definition: base_struct.h:210
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:114
#define min(a, b)
Definition: auxiliary.h:85
bool fillSingleZone(ZONE_CONTAINER *aZone, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys)
Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be mo...
std::list< ZONE_CONTAINER * > GetZoneList(bool aIncludeZonesInFootprints=false)
Function GetZoneList.
bool hasThermalConnection(D_PAD *pad, const ZONE_CONTAINER *aZone)
Return true if the given pad has a thermal connection with the given zone.
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)
void SetNeedRefill(bool aNeedRefill)
Definition: class_zone.h:177
double GetCircletoPolyCorrectionFactor(int aSegCountforCircle)