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