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  std::unique_lock<std::mutex> lock( connectivity->GetLock(), std::try_to_lock );
109 
110  if( !lock )
111  return false;
112 
113  if( m_progressReporter )
114  {
115  m_progressReporter->Report( aCheck ? _( "Checking zone fills..." ) : _( "Building zone fills..." ) );
116  m_progressReporter->SetMaxProgress( toFill.size() );
117  }
118 
119  // The board outlines is used to clip solid areas inside the board (when outlines are valid)
122 
123  for( auto zone : aZones )
124  {
125  // Keepout zones are not filled
126  if( zone->GetIsKeepout() )
127  continue;
128 
129  if( m_commit )
130  m_commit->Modify( zone );
131 
132  // calculate the hash value for filled areas. it will be used later
133  // to know if the current filled areas are up to date
134  zone->BuildHashValue();
135 
136  // Add the zone to the list of zones to test or refill
137  toFill.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST(zone) );
138 
139  // Remove existing fill first to prevent drawing invalid polygons
140  // on some platforms
141  zone->UnFill();
142  }
143 
144  std::atomic<size_t> nextItem( 0 );
145  size_t parallelThreadCount =
146  std::min<size_t>( std::thread::hardware_concurrency(), aZones.size() );
147  std::vector<std::future<size_t>> returns( parallelThreadCount );
148 
149  auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
150  {
151  size_t num = 0;
152 
153  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
154  {
155  ZONE_CONTAINER* zone = toFill[i].m_zone;
156  zone->SetFilledPolysUseThickness( filledPolyWithOutline );
157  SHAPE_POLY_SET rawPolys, finalPolys;
158  fillSingleZone( zone, rawPolys, finalPolys );
159 
160  zone->SetRawPolysList( rawPolys );
161  zone->SetFilledPolysList( finalPolys );
162  zone->SetIsFilled( true );
163 
164  if( m_progressReporter )
166 
167  num++;
168  }
169 
170  return num;
171  };
172 
173  if( parallelThreadCount <= 1 )
174  fill_lambda( m_progressReporter );
175  else
176  {
177  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
178  returns[ii] = std::async( std::launch::async, fill_lambda, m_progressReporter );
179 
180  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
181  {
182  // Here we balance returns with a 100ms timeout to allow UI updating
183  std::future_status status;
184  do
185  {
186  if( m_progressReporter )
188 
189  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
190  } while( status != std::future_status::ready );
191  }
192  }
193 
194  // Now update the connectivity to check for copper islands
195  if( m_progressReporter )
196  {
198  m_progressReporter->Report( _( "Removing insulated copper islands..." ) );
200  }
201 
202  connectivity->SetProgressReporter( m_progressReporter );
203  connectivity->FindIsolatedCopperIslands( toFill );
204 
205  // Now remove insulated copper islands and islands outside the board edge
206  bool outOfDate = false;
207 
208  for( auto& zone : toFill )
209  {
210  std::sort( zone.m_islands.begin(), zone.m_islands.end(), std::greater<int>() );
211  SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList();
212 
213  // Remove solid areas outside the board cutouts and the insulated islands
214  // only zones with net code > 0 can have insulated islands by definition
215  if( zone.m_zone->GetNetCode() > 0 )
216  {
217  // solid areas outside the board cutouts are also removed, because they are usually
218  // insulated islands
219  for( auto idx : zone.m_islands )
220  {
221  poly.DeletePolygon( idx );
222  }
223  }
224  // Zones with no net can have areas outside the board cutouts.
225  // By definition, Zones with no net have no isolated island
226  // (in fact all filled areas are isolated islands)
227  // but they can have some areas outside the board cutouts.
228  // A filled area outside the board cutouts has all points outside cutouts,
229  // so we only need to check one point for each filled polygon.
230  // Note also non copper zones are already clipped
231  else if( m_brdOutlinesValid && zone.m_zone->IsOnCopperLayer() )
232  {
233  for( int idx = 0; idx < poly.OutlineCount(); )
234  {
235  if( poly.Polygon( idx ).empty() ||
236  !m_boardOutline.Contains( poly.Polygon( idx ).front().CPoint( 0 ) ) )
237  {
238  poly.DeletePolygon( idx );
239  }
240  else
241  idx++;
242  }
243  }
244 
245  zone.m_zone->SetFilledPolysList( poly );
246 
247  if( aCheck && zone.m_zone->GetHashValue() != poly.GetHash() )
248  outOfDate = true;
249  }
250 
251  if( aCheck && outOfDate )
252  {
254  KIDIALOG dlg( m_progressReporter->GetParent(),
255  _( "Zone fills are out-of-date. Refill?" ),
256  _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
257  dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) );
258  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
259 
260  if( dlg.ShowModal() == wxID_CANCEL )
261  {
262  if( m_commit )
263  m_commit->Revert();
264 
265  connectivity->SetProgressReporter( nullptr );
266  return false;
267  }
268  }
269 
270  if( m_progressReporter )
271  {
273  m_progressReporter->Report( _( "Performing polygon fills..." ) );
274  m_progressReporter->SetMaxProgress( toFill.size() );
275  }
276 
277 
278  nextItem = 0;
279 
280  auto tri_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
281  {
282  size_t num = 0;
283 
284  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
285  {
286  toFill[i].m_zone->CacheTriangulation();
287  num++;
288 
289  if( m_progressReporter )
291  }
292 
293  return num;
294  };
295 
296  if( parallelThreadCount <= 1 )
297  tri_lambda( m_progressReporter );
298  else
299  {
300  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
301  returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter );
302 
303  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
304  {
305  // Here we balance returns with a 100ms timeout to allow UI updating
306  std::future_status status;
307  do
308  {
309  if( m_progressReporter )
311 
312  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
313  } while( status != std::future_status::ready );
314  }
315  }
316 
317  if( m_progressReporter )
318  {
320  m_progressReporter->Report( _( "Committing changes..." ) );
322  }
323 
324  connectivity->SetProgressReporter( nullptr );
325 
326  if( m_commit )
327  {
328  m_commit->Push( _( "Fill Zone(s)" ), false );
329  }
330  else
331  {
332  for( auto& i : toFill )
333  connectivity->Update( i.m_zone );
334 
335  connectivity->RecalculateRatsnest();
336  }
337 
338  return true;
339 }
340 
341 
345 bool hasThermalConnection( D_PAD* pad, const ZONE_CONTAINER* aZone )
346 {
347  // Rejects non-standard pads with tht-only thermal reliefs
348  if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
349  && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
350  {
351  return false;
352  }
353 
354  if( aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
355  && aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
356  {
357  return false;
358  }
359 
360  if( pad->GetNetCode() != aZone->GetNetCode() || pad->GetNetCode() <= 0 )
361  return false;
362 
363  EDA_RECT item_boundingbox = pad->GetBoundingBox();
364  int thermalGap = aZone->GetThermalReliefGap( pad );
365  item_boundingbox.Inflate( thermalGap, thermalGap );
366 
367  return item_boundingbox.Intersects( aZone->GetBoundingBox() );
368 }
369 
370 
375 static void setupDummyPadForHole( const D_PAD* aPad, D_PAD& aDummyPad )
376 {
377  aDummyPad.SetNetCode( aPad->GetNetCode() );
378  aDummyPad.SetSize( aPad->GetDrillSize() );
379  aDummyPad.SetOrientation( aPad->GetOrientation() );
381  : PAD_SHAPE_CIRCLE );
382  aDummyPad.SetPosition( aPad->GetPosition() );
383 }
384 
385 
390 void ZONE_FILLER::addKnockout( D_PAD* aPad, int aGap, SHAPE_POLY_SET& aHoles )
391 {
392  if( aPad->GetShape() == PAD_SHAPE_CUSTOM )
393  {
394  // the pad shape in zone can be its convex hull or the shape itself
395  SHAPE_POLY_SET outline( aPad->GetCustomShapeAsPolygon() );
396  int numSegs = std::max( GetArcToSegmentCount( aGap, m_high_def, 360.0 ), 6 );
397  double correction = GetCircletoPolyCorrectionFactor( numSegs );
398  outline.Inflate( KiROUND( aGap * correction ), numSegs );
399  aPad->CustomShapeAsPolygonToBoardPosition( &outline, aPad->GetPosition(),
400  aPad->GetOrientation() );
401 
403  {
404  std::vector<wxPoint> convex_hull;
405  BuildConvexHull( convex_hull, outline );
406 
407  aHoles.NewOutline();
408 
409  for( const wxPoint& pt : convex_hull )
410  aHoles.Append( pt );
411  }
412  else
413  aHoles.Append( outline );
414  }
415  else
416  {
417  // Optimizing polygon vertex count: the high definition is used for round
418  // and oval pads (pads with large arcs) but low def for other shapes (with
419  // small arcs)
420  if( aPad->GetShape() == PAD_SHAPE_CIRCLE || aPad->GetShape() == PAD_SHAPE_OVAL ||
421  ( aPad->GetShape() == PAD_SHAPE_ROUNDRECT && aPad->GetRoundRectRadiusRatio() > 0.4 ) )
422  aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def );
423  else
424  aPad->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_low_def );
425  }
426 }
427 
428 
433 void ZONE_FILLER::addKnockout( BOARD_ITEM* aItem, int aGap, bool aIgnoreLineWidth,
434  SHAPE_POLY_SET& aHoles )
435 {
436  switch( aItem->Type() )
437  {
438  case PCB_LINE_T:
439  {
440  DRAWSEGMENT* seg = (DRAWSEGMENT*) aItem;
441  seg->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth );
442  break;
443  }
444  case PCB_TEXT_T:
445  {
446  TEXTE_PCB* text = (TEXTE_PCB*) aItem;
447  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
448  break;
449  }
450  case PCB_MODULE_EDGE_T:
451  {
452  EDGE_MODULE* edge = (EDGE_MODULE*) aItem;
453  edge->TransformShapeWithClearanceToPolygon( aHoles, aGap, m_high_def, aIgnoreLineWidth );
454  break;
455  }
456  case PCB_MODULE_TEXT_T:
457  {
458  TEXTE_MODULE* text = (TEXTE_MODULE*) aItem;
459 
460  if( text->IsVisible() )
461  text->TransformBoundingBoxWithClearanceToPolygon( &aHoles, aGap );
462 
463  break;
464  }
465  default:
466  break;
467  }
468 }
469 
470 
476 {
477  SHAPE_POLY_SET holes;
478 
479  // Use a dummy pad to calculate relief when a pad has a hole but is not on the zone's
480  // copper layer. The dummy pad has the size and shape of the original pad's hole. We have
481  // to give it a parent because some functions expect a non-null parent to find clearance
482  // data, etc.
483  MODULE dummymodule( m_board );
484  D_PAD dummypad( &dummymodule );
485 
486  for( auto module : m_board->Modules() )
487  {
488  for( auto pad : module->Pads() )
489  {
490  if( !hasThermalConnection( pad, aZone ) )
491  continue;
492 
493  // If the pad isn't on the current layer but has a hole, knock out a thermal relief
494  // for the hole.
495  if( !pad->IsOnLayer( aZone->GetLayer() ) )
496  {
497  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
498  continue;
499 
500  setupDummyPadForHole( pad, dummypad );
501  pad = &dummypad;
502  }
503 
504  addKnockout( pad, aZone->GetThermalReliefGap( pad ), holes );
505  }
506  }
507 
510 }
511 
512 
518 {
519  int zone_clearance = aZone->GetClearance();
520  int edgeClearance = m_board->GetDesignSettings().m_CopperEdgeClearance;
521  int zone_to_edgecut_clearance = std::max( aZone->GetZoneClearance(), edgeClearance );
522 
523  // items outside the zone bounding box are skipped
524  // the bounding box is the zone bounding box + the biggest clearance found in Netclass list
525  EDA_RECT zone_boundingbox = aZone->GetBoundingBox();
526  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
527  biggest_clearance = std::max( biggest_clearance, zone_clearance );
528  zone_boundingbox.Inflate( biggest_clearance );
529 
530  // Use a dummy pad to calculate hole clearance when a pad has a hole but is not on the
531  // zone's copper layer. The dummy pad has the size and shape of the original pad's hole.
532  // We have to give it a parent because some functions expect a non-null parent to find
533  // clearance data, etc.
534  MODULE dummymodule( m_board );
535  D_PAD dummypad( &dummymodule );
536 
537  // Add non-connected pad clearances
538  //
539  for( auto module : m_board->Modules() )
540  {
541  for( auto pad : module->Pads() )
542  {
543  if( !pad->IsOnLayer( aZone->GetLayer() ) )
544  {
545  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
546  continue;
547 
548  setupDummyPadForHole( pad, dummypad );
549  pad = &dummypad;
550  }
551 
552  if( pad->GetNetCode() != aZone->GetNetCode()
553  || pad->GetNetCode() <= 0
554  || aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_NONE )
555  {
556  int gap = std::max( zone_clearance, pad->GetClearance() );
557  EDA_RECT item_boundingbox = pad->GetBoundingBox();
558  item_boundingbox.Inflate( pad->GetClearance() );
559 
560  if( item_boundingbox.Intersects( zone_boundingbox ) )
561  addKnockout( pad, gap, aHoles );
562  }
563  }
564  }
565 
566  // Add non-connected track clearances
567  //
568  for( auto track : m_board->Tracks() )
569  {
570  if( !track->IsOnLayer( aZone->GetLayer() ) )
571  continue;
572 
573  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
574  continue;
575 
576  int gap = std::max( zone_clearance, track->GetClearance() );
577  EDA_RECT item_boundingbox = track->GetBoundingBox();
578 
579  if( item_boundingbox.Intersects( zone_boundingbox ) )
580  track->TransformShapeWithClearanceToPolygon( aHoles, gap, m_low_def );
581  }
582 
583  // Add graphic item clearances. They are by definition unconnected, and have no clearance
584  // definitions of their own.
585  //
586  auto doGraphicItem = [&]( BOARD_ITEM* aItem )
587  {
588  // A item on the Edge_Cuts is always seen as on any layer:
589  if( !aItem->IsOnLayer( aZone->GetLayer() ) && !aItem->IsOnLayer( Edge_Cuts ) )
590  return;
591 
592  if( !aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
593  return;
594 
595  bool ignoreLineWidth = false;
596  int gap = zone_clearance;
597 
598  if( aItem->IsOnLayer( Edge_Cuts ) )
599  {
600  gap = zone_to_edgecut_clearance;
601 
602  // edge cuts by definition don't have a width
603  ignoreLineWidth = true;
604  }
605 
606  addKnockout( aItem, gap, ignoreLineWidth, aHoles );
607  };
608 
609  for( auto module : m_board->Modules() )
610  {
611  doGraphicItem( &module->Reference() );
612  doGraphicItem( &module->Value() );
613 
614  for( auto item : module->GraphicalItems() )
615  doGraphicItem( item );
616  }
617 
618  for( auto item : m_board->Drawings() )
619  doGraphicItem( item );
620 
621  // Add zones outlines having an higher priority and keepout
622  //
623  for( int ii = 0; ii < m_board->GetAreaCount(); ii++ )
624  {
625  ZONE_CONTAINER* zone = m_board->GetArea( ii );
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  int spoke_half_w = spoke_w / 2;
912 
913  // Quick test here to possibly save us some work
914  BOX2I itemBB = pad->GetBoundingBox();
915  itemBB.Inflate( thermalReliefGap + epsilon );
916 
917  if( !( itemBB.Intersects( zoneBB ) ) )
918  continue;
919 
920  // Thermal spokes consist of segments from the pad center to points just outside
921  // the thermal relief.
922  //
923  // We use the bounding-box to lay out the spokes, but for this to work the
924  // bounding box has to be built at the same rotation as the spokes.
925 
926  wxPoint shapePos = pad->ShapePos();
927  wxPoint padPos = pad->GetPosition();
928  double padAngle = pad->GetOrientation();
929  pad->SetOrientation( 0.0 );
930  pad->SetPosition( { 0, 0 } );
931  BOX2I reliefBB = pad->GetBoundingBox();
932  pad->SetPosition( padPos );
933  pad->SetOrientation( padAngle );
934 
935  reliefBB.Inflate( thermalReliefGap + epsilon );
936 
937  // For circle pads, the thermal spoke orientation is 45 deg
938  if( pad->GetShape() == PAD_SHAPE_CIRCLE )
939  padAngle = s_RoundPadThermalSpokeAngle;
940 
941  for( int i = 0; i < 4; i++ )
942  {
943  SHAPE_LINE_CHAIN spoke;
944  switch( i )
945  {
946  case 0: // lower stub
947  spoke.Append( +spoke_half_w, -spoke_half_w );
948  spoke.Append( -spoke_half_w, -spoke_half_w );
949  spoke.Append( -spoke_half_w, reliefBB.GetBottom() );
950  spoke.Append( 0, reliefBB.GetBottom() ); // test pt
951  spoke.Append( +spoke_half_w, reliefBB.GetBottom() );
952  break;
953 
954  case 1: // upper stub
955  spoke.Append( +spoke_half_w, spoke_half_w );
956  spoke.Append( -spoke_half_w, spoke_half_w );
957  spoke.Append( -spoke_half_w, reliefBB.GetTop() );
958  spoke.Append( 0, reliefBB.GetTop() ); // test pt
959  spoke.Append( +spoke_half_w, reliefBB.GetTop() );
960  break;
961 
962  case 2: // right stub
963  spoke.Append( -spoke_half_w, spoke_half_w );
964  spoke.Append( -spoke_half_w, -spoke_half_w );
965  spoke.Append( reliefBB.GetRight(), -spoke_half_w );
966  spoke.Append( reliefBB.GetRight(), 0 ); // test pt
967  spoke.Append( reliefBB.GetRight(), spoke_half_w );
968  break;
969 
970  case 3: // left stub
971  spoke.Append( spoke_half_w, spoke_half_w );
972  spoke.Append( spoke_half_w, -spoke_half_w );
973  spoke.Append( reliefBB.GetLeft(), -spoke_half_w );
974  spoke.Append( reliefBB.GetLeft(), 0 ); // test pt
975  spoke.Append( reliefBB.GetLeft(), spoke_half_w );
976  break;
977  }
978 
979  for( int j = 0; j < spoke.PointCount(); j++ )
980  {
981  RotatePoint( spoke.Point( j ), padAngle );
982  spoke.Point( j ) += shapePos;
983  }
984 
985  spoke.SetClosed( true );
986  spoke.GenerateBBoxCache();
987  aSpokesList.push_back( std::move( spoke ) );
988  }
989  }
990  }
991 }
992 
993 
995 {
996  // Build grid:
997 
998  // obvously line thickness must be > zone min thickness. However, it should be
999  // the case because the zone dialog setup ensure that. However, it can happens
1000  // if a board file was edited by hand by a python script
1001  int thickness = std::max( aZone->GetHatchFillTypeThickness(), aZone->GetMinThickness()+2 );
1002  int linethickness = thickness - aZone->GetMinThickness();
1003  int gridsize = thickness + aZone->GetHatchFillTypeGap();
1004  double orientation = aZone->GetHatchFillTypeOrientation();
1005 
1006  SHAPE_POLY_SET filledPolys = aRawPolys;
1007  // Use a area that contains the rotated bbox by orientation,
1008  // and after rotate the result by -orientation.
1009  if( orientation != 0.0 )
1010  {
1011  filledPolys.Rotate( M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1012  }
1013 
1014  BOX2I bbox = filledPolys.BBox( 0 );
1015 
1016  // Build hole shape
1017  // the hole size is aZone->GetHatchFillTypeGap(), but because the outline thickness
1018  // is aZone->GetMinThickness(), the hole shape size must be larger
1019  SHAPE_LINE_CHAIN hole_base;
1020  int hole_size = aZone->GetHatchFillTypeGap() + aZone->GetMinThickness();
1021  VECTOR2I corner( 0, 0 );;
1022  hole_base.Append( corner );
1023  corner.x += hole_size;
1024  hole_base.Append( corner );
1025  corner.y += hole_size;
1026  hole_base.Append( corner );
1027  corner.x = 0;
1028  hole_base.Append( corner );
1029  hole_base.SetClosed( true );
1030 
1031  // Calculate minimal area of a grid hole.
1032  // All holes smaller than a threshold will be removed
1033  double minimal_hole_area = hole_base.Area() / 2;
1034 
1035  // Now convert this hole to a smoothed shape:
1036  if( aZone->GetHatchFillTypeSmoothingLevel() > 0 )
1037  {
1038  // the actual size of chamfer, or rounded corner radius is the half size
1039  // of the HatchFillTypeGap scaled by aZone->GetHatchFillTypeSmoothingValue()
1040  // aZone->GetHatchFillTypeSmoothingValue() = 1.0 is the max value for the chamfer or the
1041  // radius of corner (radius = half size of the hole)
1042  int smooth_value = KiROUND( aZone->GetHatchFillTypeGap()
1043  * aZone->GetHatchFillTypeSmoothingValue() / 2 );
1044 
1045  // Minimal optimization:
1046  // make smoothing only for reasonnable smooth values, to avoid a lot of useless segments
1047  // and if the smooth value is small, use chamfer even if fillet is requested
1048  #define SMOOTH_MIN_VAL_MM 0.02
1049  #define SMOOTH_SMALL_VAL_MM 0.04
1050  if( smooth_value > Millimeter2iu( SMOOTH_MIN_VAL_MM ) )
1051  {
1052  SHAPE_POLY_SET smooth_hole;
1053  smooth_hole.AddOutline( hole_base );
1054  int smooth_level = aZone->GetHatchFillTypeSmoothingLevel();
1055 
1056  if( smooth_value < Millimeter2iu( SMOOTH_SMALL_VAL_MM ) && smooth_level > 1 )
1057  smooth_level = 1;
1058  // Use a larger smooth_value to compensate the outline tickness
1059  // (chamfer is not visible is smooth value < outline thickess)
1060  smooth_value += aZone->GetMinThickness()/2;
1061 
1062  // smooth_value cannot be bigger than the half size oh the hole:
1063  smooth_value = std::min( smooth_value, aZone->GetHatchFillTypeGap()/2 );
1064  // the error to approximate a circle by segments when smoothing corners by a arc
1065  int error_max = std::max( Millimeter2iu( 0.01), smooth_value/20 );
1066 
1067  switch( smooth_level )
1068  {
1069  case 1:
1070  // Chamfer() uses the distance from a corner to create a end point
1071  // for the chamfer.
1072  hole_base = smooth_hole.Chamfer( smooth_value ).Outline( 0 );
1073  break;
1074 
1075  default:
1076  if( aZone->GetHatchFillTypeSmoothingLevel() > 2 )
1077  error_max /= 2; // Force better smoothing
1078  hole_base = smooth_hole.Fillet( smooth_value, error_max ).Outline( 0 );
1079  break;
1080 
1081  case 0:
1082  break;
1083  };
1084  }
1085  }
1086 
1087  // Build holes
1088  SHAPE_POLY_SET holes;
1089 
1090  for( int xx = 0; ; xx++ )
1091  {
1092  int xpos = xx * gridsize;
1093 
1094  if( xpos > bbox.GetWidth() )
1095  break;
1096 
1097  for( int yy = 0; ; yy++ )
1098  {
1099  int ypos = yy * gridsize;
1100 
1101  if( ypos > bbox.GetHeight() )
1102  break;
1103 
1104  // Generate hole
1105  SHAPE_LINE_CHAIN hole( hole_base );
1106  hole.Move( VECTOR2I( xpos, ypos ) );
1107  holes.AddOutline( hole );
1108  }
1109  }
1110 
1111  holes.Move( bbox.GetPosition() );
1112 
1113  // Clamp holes to the area of filled zones with a outline thickness
1114  // > aZone->GetMinThickness() to be sure the thermal pads can be built
1115  int outline_margin = std::max( (aZone->GetMinThickness()*10)/9, linethickness/2 );
1116  filledPolys.Deflate( outline_margin, 16 );
1117  holes.BooleanIntersection( filledPolys, SHAPE_POLY_SET::PM_FAST );
1118 
1119  if( orientation != 0.0 )
1120  holes.Rotate( -M_PI/180.0 * orientation, VECTOR2I( 0,0 ) );
1121 
1122  // Now filter truncated holes to avoid small holes in pattern
1123  // It happens for holes near the zone outline
1124  for( int ii = 0; ii < holes.OutlineCount(); )
1125  {
1126  double area = holes.Outline( ii ).Area();
1127 
1128  if( area < minimal_hole_area ) // The current hole is too small: remove it
1129  holes.DeletePolygon( ii );
1130  else
1131  ++ii;
1132  }
1133 
1134  // create grid. Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to
1135  // generate strictly simple polygons needed by Gerber files and Fracture()
1136  aRawPolys.BooleanSubtract( aRawPolys, holes, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
1137 }
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:53
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:209
int GetThermalReliefCopperBridge(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:511
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:475
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:190
#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:206
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:502
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:628
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:246
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:864
#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
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:196
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...
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)