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 
55 extern void CreateThermalReliefPadPolygon( SHAPE_POLY_SET& aCornerBuffer,
56  const D_PAD& aPad,
57  int aThermalGap,
58  int aCopperThickness,
59  int aMinThicknessValue,
60  int aCircleToSegmentsCount,
61  double aCorrectionFactor,
62  double aThermalRot );
63 
64 static double s_thermalRot = 450; // angle of stubs in thermal reliefs for round pads
65 static const bool s_DumpZonesWhenFilling = false;
66 
67 ZONE_FILLER::ZONE_FILLER( BOARD* aBoard, COMMIT* aCommit ) :
68  m_board( aBoard ), m_commit( aCommit ), m_progressReporter( nullptr )
69 {
70 }
71 
72 
74 {
75 }
76 
77 
79 {
80  m_progressReporter = aReporter;
81 }
82 
83 bool ZONE_FILLER::Fill( std::vector<ZONE_CONTAINER*> aZones, bool aCheck )
84 {
85  std::vector<CN_ZONE_ISOLATED_ISLAND_LIST> toFill;
86  auto connectivity = m_board->GetConnectivity();
87 
88  std::unique_lock<std::mutex> lock( connectivity->GetLock(), std::try_to_lock );
89 
90  if( !lock )
91  return false;
92 
93  for( auto zone : aZones )
94  {
95  // Keepout zones are not filled
96  if( zone->GetIsKeepout() )
97  continue;
98 
99  if( m_commit )
100  m_commit->Modify( zone );
101 
102  // Remove existing fill first to prevent drawing invalid polygons
103  zone->UnFill();
104  toFill.emplace_back( CN_ZONE_ISOLATED_ISLAND_LIST(zone) );
105  }
106 
107  if( m_progressReporter )
108  {
109  m_progressReporter->Report( _( "Checking zone fills..." ) );
110  m_progressReporter->SetMaxProgress( toFill.size() );
111  }
112 
113  // Remove deprecaded segment zones (only found in very old boards)
115 
116  std::atomic<size_t> nextItem( 0 );
117  size_t parallelThreadCount = std::min<size_t>( std::thread::hardware_concurrency(), toFill.size() );
118  std::vector<std::future<size_t>> returns( parallelThreadCount );
119 
120  auto fill_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
121  {
122  size_t num = 0;
123 
124  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
125  {
126  ZONE_CONTAINER* zone = toFill[i].m_zone;
127 
128  if( zone->GetFillMode() == ZFM_SEGMENTS )
129  {
130  ZONE_SEGMENT_FILL segFill;
131  fillZoneWithSegments( zone, zone->GetFilledPolysList(), segFill );
132  zone->SetFillSegments( segFill );
133  }
134  else
135  {
136  SHAPE_POLY_SET rawPolys, finalPolys;
137  fillSingleZone( zone, rawPolys, finalPolys );
138 
139  zone->SetRawPolysList( rawPolys );
140  zone->SetFilledPolysList( finalPolys );
141  }
142 
143  zone->SetIsFilled( true );
144 
145  if( m_progressReporter )
147 
148  num++;
149  }
150 
151  return num;
152  };
153 
154  if( parallelThreadCount <= 1 )
155  fill_lambda( m_progressReporter );
156  else
157  {
158  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
159  returns[ii] = std::async( std::launch::async, fill_lambda, m_progressReporter );
160 
161  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
162  {
163  // Here we balance returns with a 100ms timeout to allow UI updating
164  std::future_status status;
165  do
166  {
167  if( m_progressReporter )
169 
170  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
171  } while( status != std::future_status::ready );
172  }
173  }
174 
175  // Now update the connectivity to check for copper islands
176  if( m_progressReporter )
177  {
179  m_progressReporter->Report( _( "Removing insulated copper islands..." ) );
181  }
182 
183  connectivity->SetProgressReporter( m_progressReporter );
184  connectivity->FindIsolatedCopperIslands( toFill );
185 
186  // Now remove insulated copper islands
187  bool outOfDate = false;
188 
189  for( auto& zone : toFill )
190  {
191  std::sort( zone.m_islands.begin(), zone.m_islands.end(), std::greater<int>() );
192  SHAPE_POLY_SET poly = zone.m_zone->GetFilledPolysList();
193 
194  // only zones with net code > 0 can have islands to remove by definition
195  if( zone.m_zone->GetNetCode() > 0 )
196  {
197  for( auto idx : zone.m_islands )
198  {
199  poly.DeletePolygon( idx );
200  }
201  }
202 
203  zone.m_zone->SetFilledPolysList( poly );
204 
205  if( aCheck && zone.m_lastPolys.GetHash() != poly.GetHash() )
206  outOfDate = true;
207  }
208 
209  if( aCheck )
210  {
211  bool refill = false;
212  wxCHECK( m_progressReporter, false );
213 
214  if( outOfDate )
215  {
216  m_progressReporter->Hide();
217 
218  KIDIALOG dlg( m_progressReporter->GetParent(),
219  _( "Zone fills are out-of-date. Refill?" ),
220  _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
221  dlg.SetOKCancelLabels( _( "Refill" ), _( "Continue without Refill" ) );
222  dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
223 
224  refill = ( dlg.ShowModal() == wxID_OK );
225 
226  m_progressReporter->Show();
227  }
228 
229  if( !refill )
230  {
231  if( m_commit )
232  m_commit->Revert();
233 
234  connectivity->SetProgressReporter( nullptr );
235  return false;
236  }
237  }
238 
239  if( m_progressReporter )
240  {
242  m_progressReporter->Report( _( "Performing polygon fills..." ) );
243  m_progressReporter->SetMaxProgress( toFill.size() );
244  }
245 
246 
247  nextItem = 0;
248 
249  auto tri_lambda = [&] ( PROGRESS_REPORTER* aReporter ) -> size_t
250  {
251  size_t num = 0;
252 
253  for( size_t i = nextItem++; i < toFill.size(); i = nextItem++ )
254  {
255  toFill[i].m_zone->CacheTriangulation();
256  num++;
257 
258  if( m_progressReporter )
260  }
261 
262  return num;
263  };
264 
265  if( parallelThreadCount <= 1 )
266  tri_lambda( m_progressReporter );
267  else
268  {
269  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
270  returns[ii] = std::async( std::launch::async, tri_lambda, m_progressReporter );
271 
272  for( size_t ii = 0; ii < parallelThreadCount; ++ii )
273  {
274  // Here we balance returns with a 100ms timeout to allow UI updating
275  std::future_status status;
276  do
277  {
278  if( m_progressReporter )
280 
281  status = returns[ii].wait_for( std::chrono::milliseconds( 100 ) );
282  } while( status != std::future_status::ready );
283  }
284  }
285 
286  if( m_progressReporter )
287  {
289  m_progressReporter->Report( _( "Committing changes..." ) );
291  }
292 
293  connectivity->SetProgressReporter( nullptr );
294 
295  if( m_commit )
296  {
297  m_commit->Push( _( "Fill Zone(s)" ), false );
298  }
299  else
300  {
301  for( unsigned i = 0; i < toFill.size(); i++ )
302  {
303  connectivity->Update( toFill[i].m_zone );
304  }
305 
306  connectivity->RecalculateRatsnest();
307  }
308 
309  return true;
310 }
311 
312 
314  SHAPE_POLY_SET& aFeatures ) const
315 {
316  // Set the number of segments in arc approximations
317  // Since we can no longer edit the segment count in pcbnew, we set
318  // the fill to our high-def count to avoid jagged knock-outs
319  // However, if the user has edited their zone to increase the segment count,
320  // we keep this preference
321  int segsPerCircle = std::max( aZone->GetArcSegmentCount(), ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
322 
323  /* calculates the coeff to compensate radius reduction of holes clearance
324  * due to the segment approx.
325  * For a circle the min radius is radius * cos( 2PI / segsPerCircle / 2)
326  * correctionFactor is 1 /cos( PI/segsPerCircle )
327  */
328  double correctionFactor = GetCircletoPolyCorrectionFactor( segsPerCircle );
329 
330  aFeatures.RemoveAllContours();
331 
332  int outline_half_thickness = aZone->GetMinThickness() / 2;
333 
334  // When removing holes, the holes must be expanded by outline_half_thickness
335  // to take in account the thickness of the zone outlines
336  int zone_clearance = aZone->GetClearance() + outline_half_thickness;
337 
338  // When holes are created by non copper items (edge cut items), use only
339  // the m_ZoneClearance parameter (zone clearance with no netclass clearance)
340  int zone_to_edgecut_clearance = aZone->GetZoneClearance() + outline_half_thickness;
341 
342  /* store holes (i.e. tracks and pads areas as polygons outlines)
343  * in a polygon list
344  */
345 
346  /* items ouside the zone bounding box are skipped
347  * the bounding box is the zone bounding box + the biggest clearance found in Netclass list
348  */
349  EDA_RECT item_boundingbox;
350  EDA_RECT zone_boundingbox = aZone->GetBoundingBox();
351  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
352  biggest_clearance = std::max( biggest_clearance, zone_clearance );
353  zone_boundingbox.Inflate( biggest_clearance );
354 
355  /*
356  * First : Add pads. Note: pads having the same net as zone are left in zone.
357  * Thermal shapes will be created later if necessary
358  */
359 
360  /* Use a dummy pad to calculate hole clearance when a pad is not on all copper layers
361  * and this pad has a hole
362  * This dummy pad has the size and shape of the hole
363  * Therefore, this dummy pad is a circle or an oval.
364  * A pad must have a parent because some functions expect a non null parent
365  * to find the parent board, and some other data
366  */
367  MODULE dummymodule( m_board ); // Creates a dummy parent
368  D_PAD dummypad( &dummymodule );
369 
370  for( MODULE* module = m_board->m_Modules; module; module = module->Next() )
371  {
372  D_PAD* nextpad;
373 
374  for( D_PAD* pad = module->PadsList(); pad != NULL; pad = nextpad )
375  {
376  nextpad = pad->Next(); // pad pointer can be modified by next code, so
377  // calculate the next pad here
378 
379  if( !pad->IsOnLayer( aZone->GetLayer() ) )
380  {
381  /* Test for pads that are on top or bottom only and have a hole.
382  * There are curious pads but they can be used for some components that are
383  * inside the board (in fact inside the hole. Some photo diodes and Leds are
384  * like this)
385  */
386  if( pad->GetDrillSize().x == 0 && pad->GetDrillSize().y == 0 )
387  continue;
388 
389  // Use a dummy pad to calculate a hole shape that have the same dimension as
390  // the pad hole
391  dummypad.SetSize( pad->GetDrillSize() );
392  dummypad.SetOrientation( pad->GetOrientation() );
393  dummypad.SetShape( pad->GetDrillShape() == PAD_DRILL_SHAPE_OBLONG ?
395  dummypad.SetPosition( pad->GetPosition() );
396 
397  pad = &dummypad;
398  }
399 
400  // Note: netcode <=0 means not connected item
401  if( ( pad->GetNetCode() != aZone->GetNetCode() ) || ( pad->GetNetCode() <= 0 ) )
402  {
403  int item_clearance = pad->GetClearance() + outline_half_thickness;
404  item_boundingbox = pad->GetBoundingBox();
405  item_boundingbox.Inflate( item_clearance );
406 
407  if( item_boundingbox.Intersects( zone_boundingbox ) )
408  {
409  int clearance = std::max( zone_clearance, item_clearance );
410 
411  // PAD_SHAPE_CUSTOM can have a specific keepout, to avoid to break the shape
412  if( pad->GetShape() == PAD_SHAPE_CUSTOM
413  && pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
414  {
415  // the pad shape in zone can be its convex hull or
416  // the shape itself
417  SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
418  outline.Inflate( KiROUND( clearance * correctionFactor ), segsPerCircle );
419  pad->CustomShapeAsPolygonToBoardPosition( &outline,
420  pad->GetPosition(), pad->GetOrientation() );
421 
422  if( pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
423  {
424  std::vector<wxPoint> convex_hull;
425  BuildConvexHull( convex_hull, outline );
426 
427  aFeatures.NewOutline();
428 
429  for( unsigned ii = 0; ii < convex_hull.size(); ++ii )
430  aFeatures.Append( convex_hull[ii] );
431  }
432  else
433  aFeatures.Append( outline );
434  }
435  else
436  pad->TransformShapeWithClearanceToPolygon( aFeatures,
437  clearance,
438  segsPerCircle,
439  correctionFactor );
440  }
441 
442  continue;
443  }
444 
445  // Pads are removed from zone if the setup is PAD_ZONE_CONN_NONE
446  // or if they have a custom shape and not PAD_ZONE_CONN_FULL,
447  // because a thermal relief will break
448  // the shape
449  if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_NONE
450  || ( pad->GetShape() == PAD_SHAPE_CUSTOM && aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_FULL ) )
451  {
452  int gap = zone_clearance;
453  int thermalGap = aZone->GetThermalReliefGap( pad );
454  gap = std::max( gap, thermalGap );
455  item_boundingbox = pad->GetBoundingBox();
456  item_boundingbox.Inflate( gap );
457 
458  if( item_boundingbox.Intersects( zone_boundingbox ) )
459  {
460  // PAD_SHAPE_CUSTOM has a specific keepout, to avoid to break the shape
461  // the pad shape in zone can be its convex hull or the shape itself
462  if( pad->GetShape() == PAD_SHAPE_CUSTOM
463  && pad->GetCustomShapeInZoneOpt() == CUST_PAD_SHAPE_IN_ZONE_CONVEXHULL )
464  {
465  // the pad shape in zone can be its convex hull or
466  // the shape itself
467  SHAPE_POLY_SET outline( pad->GetCustomShapeAsPolygon() );
468  outline.Inflate( KiROUND( gap * correctionFactor ), segsPerCircle );
469  pad->CustomShapeAsPolygonToBoardPosition( &outline,
470  pad->GetPosition(), pad->GetOrientation() );
471 
472  std::vector<wxPoint> convex_hull;
473  BuildConvexHull( convex_hull, outline );
474 
475  aFeatures.NewOutline();
476 
477  for( unsigned ii = 0; ii < convex_hull.size(); ++ii )
478  aFeatures.Append( convex_hull[ii] );
479  }
480  else
481  pad->TransformShapeWithClearanceToPolygon( aFeatures,
482  gap, segsPerCircle, correctionFactor );
483  }
484  }
485  }
486  }
487 
488  /* Add holes (i.e. tracks and vias areas as polygons outlines)
489  * in cornerBufferPolysToSubstract
490  */
491  for( auto track : m_board->Tracks() )
492  {
493  if( !track->IsOnLayer( aZone->GetLayer() ) )
494  continue;
495 
496  if( track->GetNetCode() == aZone->GetNetCode() && ( aZone->GetNetCode() != 0) )
497  continue;
498 
499  int item_clearance = track->GetClearance() + outline_half_thickness;
500  item_boundingbox = track->GetBoundingBox();
501 
502  if( item_boundingbox.Intersects( zone_boundingbox ) )
503  {
504  int clearance = std::max( zone_clearance, item_clearance );
505  track->TransformShapeWithClearanceToPolygon( aFeatures,
506  clearance, segsPerCircle, correctionFactor );
507  }
508  }
509 
510  /* Add graphic items that are on copper layers. These have no net, so we just
511  * use the zone clearance (or edge clearance).
512  */
513  auto doGraphicItem = [&]( BOARD_ITEM* aItem )
514  {
515  // A item on the Edge_Cuts is always seen as on any layer:
516  if( !aItem->IsOnLayer( aZone->GetLayer() ) && !aItem->IsOnLayer( Edge_Cuts ) )
517  return;
518 
519  if( !aItem->GetBoundingBox().Intersects( zone_boundingbox ) )
520  return;
521 
522  bool ignoreLineWidth = false;
523  int zclearance = zone_clearance;
524 
525  if( aItem->IsOnLayer( Edge_Cuts ) )
526  {
527  // use only the m_ZoneClearance, not the clearance using
528  // the netclass value, because we do not have a copper item
529  zclearance = zone_to_edgecut_clearance;
530 
531 #if 0
532 // 6.0 TODO: we're leaving this off for 5.1 so that people can continue to use the board
533 // edge width as a hack for edge clearance.
534  // edge cuts by definition don't have a width
535  ignoreLineWidth = true;
536 #endif
537  }
538 
539  switch( aItem->Type() )
540  {
541  case PCB_LINE_T:
542  static_cast<DRAWSEGMENT*>( aItem )->TransformShapeWithClearanceToPolygon(
543  aFeatures, zclearance, segsPerCircle, correctionFactor, ignoreLineWidth );
544  break;
545 
546  case PCB_TEXT_T:
547  static_cast<TEXTE_PCB*>( aItem )->TransformBoundingBoxWithClearanceToPolygon(
548  &aFeatures, zclearance );
549  break;
550 
551  case PCB_MODULE_EDGE_T:
552  static_cast<EDGE_MODULE*>( aItem )->TransformShapeWithClearanceToPolygon(
553  aFeatures, zclearance, segsPerCircle, correctionFactor, ignoreLineWidth );
554  break;
555 
556  case PCB_MODULE_TEXT_T:
557  if( static_cast<TEXTE_MODULE*>( aItem )->IsVisible() )
558  {
559  static_cast<TEXTE_MODULE*>( aItem )->TransformBoundingBoxWithClearanceToPolygon(
560  &aFeatures, zclearance );
561  }
562  break;
563 
564  default:
565  break;
566  }
567  };
568 
569  for( auto module : m_board->Modules() )
570  {
571  doGraphicItem( &module->Reference() );
572  doGraphicItem( &module->Value() );
573 
574  for( auto item : module->GraphicalItems() )
575  doGraphicItem( item );
576  }
577 
578  for( auto item : m_board->Drawings() )
579  doGraphicItem( item );
580 
581  /* Add zones outlines having an higher priority and keepout
582  */
583  for( int ii = 0; ii < m_board->GetAreaCount(); ii++ )
584  {
585  ZONE_CONTAINER* zone = m_board->GetArea( ii );
586 
587  // If the zones share no common layers
588  if( !aZone->CommonLayerExists( zone->GetLayerSet() ) )
589  continue;
590 
591  if( !zone->GetIsKeepout() && zone->GetPriority() <= aZone->GetPriority() )
592  continue;
593 
594  if( zone->GetIsKeepout() && !zone->GetDoNotAllowCopperPour() )
595  continue;
596 
597  // A highter priority zone or keepout area is found: remove this area
598  item_boundingbox = zone->GetBoundingBox();
599 
600  if( !item_boundingbox.Intersects( zone_boundingbox ) )
601  continue;
602 
603  // Add the zone outline area.
604  // However if the zone has the same net as the current zone,
605  // do not add any clearance.
606  // the zone will be connected to the current zone, but filled areas
607  // will use different parameters (clearance, thermal shapes )
608  bool same_net = aZone->GetNetCode() == zone->GetNetCode();
609  bool use_net_clearance = true;
610  int min_clearance = zone_clearance;
611 
612  // Do not forget to make room to draw the thick outlines
613  // of the hole created by the area of the zone to remove
614  int holeclearance = zone->GetClearance() + outline_half_thickness;
615 
616  // The final clearance is obviously the max value of each zone clearance
617  min_clearance = std::max( min_clearance, holeclearance );
618 
619  if( zone->GetIsKeepout() || same_net )
620  {
621  // Just take in account the fact the outline has a thickness, so
622  // the actual area to substract is inflated to take in account this fact
623  min_clearance = outline_half_thickness;
624  use_net_clearance = false;
625  }
626 
628  aFeatures, min_clearance, use_net_clearance );
629  }
630 
631  /* Remove thermal symbols
632  */
633  for( auto module : m_board->Modules() )
634  {
635  for( auto pad : module->Pads() )
636  {
637  // Rejects non-standard pads with tht-only thermal reliefs
638  if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
639  && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
640  continue;
641 
642  if( aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
643  && aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
644  continue;
645 
646  if( !pad->IsOnLayer( aZone->GetLayer() ) )
647  continue;
648 
649  if( pad->GetNetCode() != aZone->GetNetCode() )
650  continue;
651 
652  if( pad->GetNetCode() <= 0 )
653  continue;
654 
655  item_boundingbox = pad->GetBoundingBox();
656  int thermalGap = aZone->GetThermalReliefGap( pad );
657  item_boundingbox.Inflate( thermalGap, thermalGap );
658 
659  if( item_boundingbox.Intersects( zone_boundingbox ) )
660  {
662  *pad, thermalGap,
663  aZone->GetThermalReliefCopperBridge( pad ),
664  aZone->GetMinThickness(),
665  segsPerCircle,
666  correctionFactor, s_thermalRot );
667  }
668  }
669  }
670 }
671 
702  const SHAPE_POLY_SET& aSmoothedOutline,
703  SHAPE_POLY_SET& aRawPolys,
704  SHAPE_POLY_SET& aFinalPolys ) const
705 {
706  int outline_half_thickness = aZone->GetMinThickness() / 2;
707 
708  std::unique_ptr<SHAPE_FILE_IO> dumper( new SHAPE_FILE_IO(
709  s_DumpZonesWhenFilling ? "zones_dump.txt" : "", SHAPE_FILE_IO::IOM_APPEND ) );
710 
711  // Set the number of segments in arc approximations
712  int segsPerCircle = std::max( aZone->GetArcSegmentCount(), ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
713 
714  /* calculates the coeff to compensate radius reduction of holes clearance
715  */
716  double correctionFactor = GetCircletoPolyCorrectionFactor( segsPerCircle );
717 
719  dumper->BeginGroup( "clipper-zone" );
720 
721  SHAPE_POLY_SET solidAreas = aSmoothedOutline;
722 
723  solidAreas.Inflate( -outline_half_thickness, segsPerCircle );
724  solidAreas.Simplify( SHAPE_POLY_SET::PM_FAST );
725 
726  SHAPE_POLY_SET holes;
727 
729  dumper->Write( &solidAreas, "solid-areas" );
730 
731  buildZoneFeatureHoleList( aZone, holes );
732 
734  dumper->Write( &holes, "feature-holes" );
735 
737 
739  dumper->Write( &holes, "feature-holes-postsimplify" );
740 
741  // Generate the filled areas (currently, without thermal shapes, which will
742  // be created later).
743  // Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to generate strictly simple polygons
744  // needed by Gerber files and Fracture()
746 
748  dumper->Write( &solidAreas, "solid-areas-minus-holes" );
749 
750  // Test thermal stubs connections and add polygons to remove unconnected stubs.
751  // (this is a refinement for thermal relief shapes)
752  // Note: we are using not fractured solid area polygons, to avoid a side effect of extra segments
753  // created by Fracture(): if a tested point used in buildUnconnectedThermalStubsPolygonList
754  // is on a extra segment, the tested point is seen outside the solid area, but it is inside.
755  // This is not a bug, just the fact when a point is on a polygon outline, it is hard to say
756  // if it is inside or outside the polygon.
757  SHAPE_POLY_SET thermalHoles;
758 
759  if( aZone->GetNetCode() > 0 )
760  {
761  buildUnconnectedThermalStubsPolygonList( thermalHoles, aZone, solidAreas,
762  correctionFactor, s_thermalRot );
763 
764  }
765 
766  // remove copper areas corresponding to not connected stubs
767  if( !thermalHoles.IsEmpty() )
768  {
769  thermalHoles.Simplify( SHAPE_POLY_SET::PM_FAST );
770  // Remove unconnected stubs. Use SHAPE_POLY_SET::PM_STRICTLY_SIMPLE to
771  // generate strictly simple polygons
772  // needed by Gerber files and Fracture()
773  solidAreas.BooleanSubtract( thermalHoles, SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
774 
776  dumper->Write( &thermalHoles, "thermal-holes" );
777 
778  // put these areas in m_FilledPolysList
779  SHAPE_POLY_SET th_fractured = solidAreas;
780  th_fractured.Fracture( SHAPE_POLY_SET::PM_FAST );
781 
783  dumper->Write( &th_fractured, "th_fractured" );
784 
785  aFinalPolys = th_fractured;
786  }
787  else
788  {
789  SHAPE_POLY_SET areas_fractured = solidAreas;
790  areas_fractured.Fracture( SHAPE_POLY_SET::PM_FAST );
791 
793  dumper->Write( &areas_fractured, "areas_fractured" );
794 
795  aFinalPolys = areas_fractured;
796  }
797 
798  aRawPolys = aFinalPolys;
799 
801  dumper->EndGroup();
802 }
803 
804 /* Build the filled solid areas data from real outlines (stored in m_Poly)
805  * The solid areas can be more than one on copper layers, and do not have holes
806  * ( holes are linked by overlapping segments to the main outline)
807  */
809  SHAPE_POLY_SET& aFinalPolys ) const
810 {
811  SHAPE_POLY_SET smoothedPoly;
812 
813  /* convert outlines + holes to outlines without holes (adding extra segments if necessary)
814  * m_Poly data is expected normalized, i.e. NormalizeAreaOutlines was used after building
815  * this zone
816  */
817  if ( !aZone->BuildSmoothedPoly( smoothedPoly ) )
818  return false;
819 
820  if( aZone->IsOnCopperLayer() )
821  {
822  computeRawFilledAreas( aZone, smoothedPoly, aRawPolys, aFinalPolys );
823  }
824  else
825  {
826  aRawPolys = smoothedPoly;
827  aFinalPolys = smoothedPoly;
828  aFinalPolys.Inflate( -aZone->GetMinThickness() / 2, ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF );
829  aFinalPolys.Fracture( SHAPE_POLY_SET::PM_FAST );
830  }
831 
832  aZone->SetNeedRefill( false );
833  return true;
834 }
835 
837  const SHAPE_POLY_SET& aFilledPolys,
838  ZONE_SEGMENT_FILL& aFillSegs ) const
839 {
840  bool success = true;
841  // segments are on something like a grid. Give it a minimal size
842  // to avoid too many segments, and use the m_ZoneMinThickness when (this is usually the case)
843  // the size is > mingrid_size.
844  // This is not perfect, but the actual purpose of this code
845  // is to allow filling zones on a grid, with grid size > m_ZoneMinThickness,
846  // in order to have really a grid.
847  //
848  // Using a user selectable grid size is for future Kicad versions.
849  // For now the area is fully filled.
850  int mingrid_size = Millimeter2iu( 0.05 );
851  int grid_size = std::max( mingrid_size, aZone->GetMinThickness() );
852  // Make segments slightly overlapping to ensure a good full filling
853  grid_size -= grid_size/20;
854 
855  // Creates the horizontal segments
856  for ( int index = 0; index < aFilledPolys.OutlineCount(); index++ )
857  {
858  const SHAPE_LINE_CHAIN& outline0 = aFilledPolys.COutline( index );
859  success = fillPolygonWithHorizontalSegments( outline0, aFillSegs, grid_size );
860 
861  if( !success )
862  break;
863 
864  // Creates the vertical segments. Because the filling algo creates horizontal segments,
865  // to reuse the fillPolygonWithHorizontalSegments function, we rotate the polygons to fill
866  // then fill them, then inverse rotate the result
867  SHAPE_LINE_CHAIN outline90;
868  outline90.Append( outline0 );
869 
870  // Rotate 90 degrees the outline:
871  for( int ii = 0; ii < outline90.PointCount(); ii++ )
872  {
873  VECTOR2I& point = outline90.Point( ii );
874  std::swap( point.x, point.y );
875  point.y = -point.y;
876  }
877 
878  int first_point = aFillSegs.size();
879  success = fillPolygonWithHorizontalSegments( outline90, aFillSegs, grid_size );
880 
881  if( !success )
882  break;
883 
884  // Rotate -90 degrees the segments:
885  for( unsigned ii = first_point; ii < aFillSegs.size(); ii++ )
886  {
887  SEG& segm = aFillSegs[ii];
888  std::swap( segm.A.x, segm.A.y );
889  std::swap( segm.B.x, segm.B.y );
890  segm.A.x = - segm.A.x;
891  segm.B.x = - segm.B.x;
892  }
893  }
894 
895  aZone->SetNeedRefill( false );
896  return success;
897 }
898 
908  ZONE_SEGMENT_FILL& aFillSegmList, int aStep ) const
909 {
910  std::vector <int> x_coordinates;
911  bool success = true;
912 
913  // Creates the horizontal segments
914  const SHAPE_LINE_CHAIN& outline = aPolygon;
915  const BOX2I& rect = outline.BBox();
916 
917  // Calculate the y limits of the zone
918  for( int refy = rect.GetY(), endy = rect.GetBottom(); refy < endy; refy += aStep )
919  {
920  // find all intersection points of an infinite line with polyline sides
921  x_coordinates.clear();
922 
923  for( int v = 0; v < outline.PointCount(); v++ )
924  {
925 
926  int seg_startX = outline.CPoint( v ).x;
927  int seg_startY = outline.CPoint( v ).y;
928  int seg_endX = outline.CPoint( v + 1 ).x;
929  int seg_endY = outline.CPoint( v + 1 ).y;
930 
931  /* Trivial cases: skip if ref above or below the segment to test */
932  if( ( seg_startY > refy ) && ( seg_endY > refy ) )
933  continue;
934 
935  // segment below ref point, or its Y end pos on Y coordinate ref point: skip
936  if( ( seg_startY <= refy ) && (seg_endY <= refy ) )
937  continue;
938 
939  /* at this point refy is between seg_startY and seg_endY
940  * see if an horizontal line at Y = refy is intersecting this segment
941  */
942  // calculate the x position of the intersection of this segment and the
943  // infinite line this is more easier if we move the X,Y axis origin to
944  // the segment start point:
945 
946  seg_endX -= seg_startX;
947  seg_endY -= seg_startY;
948  double newrefy = (double) ( refy - seg_startY );
949  double intersec_x;
950 
951  if ( seg_endY == 0 ) // horizontal segment on the same line: skip
952  continue;
953 
954  // Now calculate the x intersection coordinate of the horizontal line at
955  // y = newrefy and the segment from (0,0) to (seg_endX,seg_endY) with the
956  // horizontal line at the new refy position the line slope is:
957  // slope = seg_endY/seg_endX; and inv_slope = seg_endX/seg_endY
958  // and the x pos relative to the new origin is:
959  // intersec_x = refy/slope = refy * inv_slope
960  // Note: because horizontal segments are already tested and skipped, slope
961  // exists (seg_end_y not O)
962  double inv_slope = (double) seg_endX / seg_endY;
963  intersec_x = newrefy * inv_slope;
964  x_coordinates.push_back( (int) intersec_x + seg_startX );
965  }
966 
967  // A line scan is finished: build list of segments
968 
969  // Sort intersection points by increasing x value:
970  // So 2 consecutive points are the ends of a segment
971  std::sort( x_coordinates.begin(), x_coordinates.end() );
972 
973  // An even number of coordinates is expected, because a segment has 2 ends.
974  // An if this algorithm always works, it must always find an even count.
975  if( ( x_coordinates.size() & 1 ) != 0 )
976  {
977  success = false;
978  break;
979  }
980 
981  // Create segments having the same Y coordinate
982  int iimax = x_coordinates.size() - 1;
983 
984  for( int ii = 0; ii < iimax; ii += 2 )
985  {
986  VECTOR2I seg_start, seg_end;
987  seg_start.x = x_coordinates[ii];
988  seg_start.y = refy;
989  seg_end.x = x_coordinates[ii + 1];
990  seg_end.y = refy;
991  SEG segment( seg_start, seg_end );
992  aFillSegmList.push_back( segment );
993  }
994  } // End examine segments in one area
995 
996  return success;
997 }
998 
999 
1011  const ZONE_CONTAINER* aZone,
1012  const SHAPE_POLY_SET& aRawFilledArea,
1013  double aArcCorrection,
1014  double aRoundPadThermalRotation ) const
1015 {
1016  SHAPE_LINE_CHAIN spokes;
1017  BOX2I itemBB;
1018  VECTOR2I ptTest[4];
1019  auto zoneBB = aRawFilledArea.BBox();
1020 
1021 
1022  int zone_clearance = aZone->GetZoneClearance();
1023 
1024  int biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
1025  biggest_clearance = std::max( biggest_clearance, zone_clearance );
1026  zoneBB.Inflate( biggest_clearance );
1027 
1028  // half size of the pen used to draw/plot zones outlines
1029  int pen_radius = aZone->GetMinThickness() / 2;
1030 
1031  for( auto module : m_board->Modules() )
1032  {
1033  for( auto pad : module->Pads() )
1034  {
1035  // Rejects non-standard pads with tht-only thermal reliefs
1036  if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
1037  && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
1038  continue;
1039 
1040  if( aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
1041  && aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
1042  continue;
1043 
1044  if( !pad->IsOnLayer( aZone->GetLayer() ) )
1045  continue;
1046 
1047  if( pad->GetNetCode() != aZone->GetNetCode() )
1048  continue;
1049 
1050  // Calculate thermal bridge half width
1051  int thermalBridgeWidth = aZone->GetThermalReliefCopperBridge( pad )
1052  - aZone->GetMinThickness();
1053  if( thermalBridgeWidth <= 0 )
1054  continue;
1055 
1056  // we need the thermal bridge half width
1057  // with a small extra size to be sure we create a stub
1058  // slightly larger than the actual stub
1059  thermalBridgeWidth = ( thermalBridgeWidth + 4 ) / 2;
1060 
1061  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
1062 
1063  itemBB = pad->GetBoundingBox();
1064  itemBB.Inflate( thermalReliefGap );
1065  if( !( itemBB.Intersects( zoneBB ) ) )
1066  continue;
1067 
1068  // Thermal bridges are like a segment from a starting point inside the pad
1069  // to an ending point outside the pad
1070 
1071  // calculate the ending point of the thermal pad, outside the pad
1072  VECTOR2I endpoint;
1073  endpoint.x = ( pad->GetSize().x / 2 ) + thermalReliefGap;
1074  endpoint.y = ( pad->GetSize().y / 2 ) + thermalReliefGap;
1075 
1076  // Calculate the starting point of the thermal stub
1077  // inside the pad
1078  VECTOR2I startpoint;
1079  int copperThickness = aZone->GetThermalReliefCopperBridge( pad )
1080  - aZone->GetMinThickness();
1081 
1082  if( copperThickness < 0 )
1083  copperThickness = 0;
1084 
1085  // Leave a small extra size to the copper area inside to pad
1086  copperThickness += KiROUND( IU_PER_MM * 0.04 );
1087 
1088  startpoint.x = std::min( pad->GetSize().x, copperThickness );
1089  startpoint.y = std::min( pad->GetSize().y, copperThickness );
1090 
1091  startpoint.x /= 2;
1092  startpoint.y /= 2;
1093 
1094  // This is a CIRCLE pad tweak
1095  // for circle pads, the thermal stubs orientation is 45 deg
1096  double fAngle = pad->GetOrientation();
1097  if( pad->GetShape() == PAD_SHAPE_CIRCLE )
1098  {
1099  endpoint.x = KiROUND( endpoint.x * aArcCorrection );
1100  endpoint.y = endpoint.x;
1101  fAngle = aRoundPadThermalRotation;
1102  }
1103 
1104  // contour line width has to be taken into calculation to avoid "thermal stub bleed"
1105  endpoint.x += pen_radius;
1106  endpoint.y += pen_radius;
1107  // compute north, south, west and east points for zone connection.
1108  ptTest[0] = VECTOR2I( 0, endpoint.y ); // lower point
1109  ptTest[1] = VECTOR2I( 0, -endpoint.y ); // upper point
1110  ptTest[2] = VECTOR2I( endpoint.x, 0 ); // right point
1111  ptTest[3] = VECTOR2I( -endpoint.x, 0 ); // left point
1112 
1113  // Test all sides
1114  for( int i = 0; i < 4; i++ )
1115  {
1116  // rotate point
1117  RotatePoint( ptTest[i], fAngle );
1118 
1119  // translate point
1120  ptTest[i] += pad->ShapePos();
1121 
1122  if( aRawFilledArea.Contains( ptTest[i] ) )
1123  continue;
1124 
1125  spokes.Clear();
1126 
1127  // polygons are rectangles with width of copper bridge value
1128  switch( i )
1129  {
1130  case 0: // lower stub
1131  spokes.Append( -thermalBridgeWidth, endpoint.y );
1132  spokes.Append( +thermalBridgeWidth, endpoint.y );
1133  spokes.Append( +thermalBridgeWidth, startpoint.y );
1134  spokes.Append( -thermalBridgeWidth, startpoint.y );
1135  break;
1136 
1137  case 1: // upper stub
1138  spokes.Append( -thermalBridgeWidth, -endpoint.y );
1139  spokes.Append( +thermalBridgeWidth, -endpoint.y );
1140  spokes.Append( +thermalBridgeWidth, -startpoint.y );
1141  spokes.Append( -thermalBridgeWidth, -startpoint.y );
1142  break;
1143 
1144  case 2: // right stub
1145  spokes.Append( endpoint.x, -thermalBridgeWidth );
1146  spokes.Append( endpoint.x, thermalBridgeWidth );
1147  spokes.Append( +startpoint.x, thermalBridgeWidth );
1148  spokes.Append( +startpoint.x, -thermalBridgeWidth );
1149  break;
1150 
1151  case 3: // left stub
1152  spokes.Append( -endpoint.x, -thermalBridgeWidth );
1153  spokes.Append( -endpoint.x, thermalBridgeWidth );
1154  spokes.Append( -startpoint.x, thermalBridgeWidth );
1155  spokes.Append( -startpoint.x, -thermalBridgeWidth );
1156  break;
1157  }
1158 
1159  aCornerBuffer.NewOutline();
1160 
1161  // add computed polygon to list
1162  for( int ic = 0; ic < spokes.PointCount(); ic++ )
1163  {
1164  auto cpos = spokes.CPoint( ic );
1165  RotatePoint( cpos, fAngle ); // Rotate according to module orientation
1166  cpos += pad->ShapePos(); // Shift origin to position
1167  aCornerBuffer.Append( cpos );
1168  }
1169  }
1170  }
1171  }
1172 }
void SetFilledPolysList(SHAPE_POLY_SET &aPolysList)
Function SetFilledPolysList sets the list of filled polygons.
Definition: class_zone.h:580
virtual void Revert()=0
Revertes the commit by restoring the modifed items state.
D_PAD * Next() const
Definition: class_pad.h:160
void AdvancePhase()
Uses the next vailable virtual zone of the dialog progress bar.
bool Contains(const VECTOR2I &aP, int aSubpolyIndex=-1, bool aIgnoreHoles=false) const
Returns true if a given subpolygon contains the point aP.
Class ZONE_CONTAINER handles a list of polygons defining a copper zone.
Definition: class_zone.h:59
COMMIT & Modify(EDA_ITEM *aItem)
Modifies a given item in the model.
Definition: commit.h:103
std::vector< SEG > ZONE_SEGMENT_FILL
Definition: class_zone.h:49
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox
Definition: confirm.cpp:61
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.
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:198
int GetThermalReliefCopperBridge(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:640
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:121
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:117
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox (virtual)
Definition: class_zone.cpp:521
int GetBiggestClearanceValue()
Function GetBiggestClearanceValue.
A progress reporter for use in multi-threaded environments.
void TransformOutlinesShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aMinClearanceValue, bool aUseNetClearance) const
Function TransformOutlinesShapeWithClearanceToPolygon Convert the outlines shape to a polygon with no...
Class BOARD to handle a board.
WX_PROGRESS_REPORTER * m_progressReporter
Definition: zone_filler.h:119
bool IsEmpty() const
Returns true if the set is empty (no polygons at all)
virtual PCB_LAYER_ID GetLayer() const override
Function GetLayer returns the primary layer this item is on.
Definition: class_zone.cpp:179
void Report(const wxString &aMessage)
Display aMessage in the progress bar dialog.
class TEXTE_PCB, text on a layer
Definition: typeinfo.h:92
void SetPosition(const wxPoint &aPos) override
Definition: class_pad.h:219
Classes to handle copper zones.
Class COMMIT.
Definition: commit.h:71
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:539
void SetFillSegments(const ZONE_SEGMENT_FILL &aSegments)
Definition: class_zone.h:618
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:216
coord_type GetBottom() const
Definition: box2.h:198
void DeleteAll()
Function DeleteAll deletes all items on the list and leaves the list empty.
Definition: dlist.cpp:44
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:631
VECTOR2< int > VECTOR2I
Definition: vector2d.h:587
void SetIsFilled(bool isFilled)
Definition: class_zone.h:189
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:65
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:780
Functions relatives to tracks, vias and segments used to fill zones.
void Append(int aX, int aY, bool aAllowDuplication=false)
Function Append()
void DeletePolygon(int aIdx)
Deletes aIdx-th polygon from the set
Pads are not covered.
Definition: zones.h:52
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:237
bool Intersects(const BOX2< Vec > &aRect) const
Function Intersects.
Definition: box2.h:234
const VECTOR2I & CPoint(int aIndex) const
Function CPoint()
int GetArcSegmentCount() const
Definition: class_zone.h:186
void SetProgressReporter(WX_PROGRESS_REPORTER *aReporter)
Definition: zone_filler.cpp:78
int GetAreaCount() const
Function GetAreaCount.
Definition: class_board.h:1026
bool fillPolygonWithHorizontalSegments(const SHAPE_LINE_CHAIN &aPolygon, ZONE_SEGMENT_FILL &aFillSegmList, int aStep) const
Helper function fillPolygonWithHorizontalSegments fills a polygon with horizontal segments.
const BOX2I BBox(int aClearance=0) const override
Function BBox()
void Inflate(int aFactor, int aCircleSegmentsCount)
Performs outline inflation/deflation, using round corners.
DLIST_ITERATOR_WRAPPER< MODULE > Modules()
Definition: class_board.h:255
COMMIT * m_commit
Definition: zone_filler.h:118
Class SHAPE_POLY_SET.
ZONE_FILLER(BOARD *aBoard, COMMIT *aCommit=nullptr)
Definition: zone_filler.cpp:67
ZONE_FILL_MODE GetFillMode() const
Definition: class_zone.h:171
DLIST< SEGZONE > m_SegZoneDeprecated
Definition: class_board.h:251
void CreateThermalReliefPadPolygon(SHAPE_POLY_SET &aCornerBuffer, const D_PAD &aPad, int aThermalGap, int aCopperThickness, int aMinThicknessValue, int aCircleToSegmentsCount, double aCorrectionFactor, double aThermalRot)
Function CreateThermalReliefPadPolygon Add holes around a pad to create a thermal relief copper thick...
bool GetDoNotAllowCopperPour() const
Definition: class_zone.h:638
bool Fill(std::vector< ZONE_CONTAINER * > aZones, bool aCheck=false)
Definition: zone_filler.cpp:83
std::shared_ptr< CONNECTIVITY_DATA > GetConnectivity() const
Function GetConnectivity() returns list of missing connections between components/tracks.
Definition: class_board.h:297
void SetSize(const wxSize &aSize)
Definition: class_pad.h:268
a few functions useful in geometry calculations.
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
void buildZoneFeatureHoleList(const ZONE_CONTAINER *aZone, SHAPE_POLY_SET &aFeatures) const
int NewOutline()
Creates a new empty polygon in the set and returns its index
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:589
bool GetIsKeepout() const
Accessors to parameters used in Keepout zones:
Definition: class_zone.h:637
static double s_thermalRot
Definition: zone_filler.cpp:64
class TEXTE_MODULE, text in a footprint
Definition: typeinfo.h:93
Definition: seg.h:36
void buildUnconnectedThermalStubsPolygonList(SHAPE_POLY_SET &aCornerBuffer, const ZONE_CONTAINER *aZone, const SHAPE_POLY_SET &aRawFilledArea, double aArcCorrection, double aRoundPadThermalRotation) const
Function buildUnconnectedThermalStubsPolygonList Creates a set of polygons corresponding to stubs cre...
coord_type GetY() const
Definition: box2.h:189
void computeRawFilledAreas(const ZONE_CONTAINER *aZone, const SHAPE_POLY_SET &aSmoothedOutline, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys) const
Function computeRawFilledAreas Add non copper areas polygons (pads and tracks with clearance) to a fi...
bool BuildSmoothedPoly(SHAPE_POLY_SET &aSmoothedPoly) const
Function GetSmoothedPoly returns a pointer to the corner-smoothed version of m_Poly if it exists,...
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:97
Class to handle a graphic segment.
ZoneConnection GetPadConnection(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:999
#define max(a, b)
Definition: auxiliary.h:86
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:171
DLIST< MODULE > m_Modules
Definition: class_board.h:249
bool fillZoneWithSegments(ZONE_CONTAINER *aZone, const SHAPE_POLY_SET &aFilledPolys, ZONE_SEGMENT_FILL &aFillSegs) const
Function fillZoneWithSegments Fill sub areas in a zone with segments with m_ZoneMinThickness width A ...
Class SHAPE_LINE_CHAIN.
const SHAPE_LINE_CHAIN & COutline(int aIndex) const
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.
VECTOR2I A
Definition: seg.h:44
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
int GetMinThickness() const
Definition: class_zone.h:200
int GetClearance(BOARD_CONNECTED_ITEM *aItem=NULL) const override
Function GetClearance returns the clearance in internal units.
Definition: class_pad.cpp:608
void SetShape(PAD_SHAPE_T aShape)
Definition: class_pad.h:217
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:429
void Clear()
Function Clear() Removes all points from the line chain.
bool fillSingleZone(ZONE_CONTAINER *aZone, SHAPE_POLY_SET &aRawPolys, SHAPE_POLY_SET &aFinalPolys) const
Build the filled solid areas polygons from zone outlines (stored in m_Poly) The solid areas can be mo...
VECTOR2I & Point(int aIndex)
Function Point()
PCB_TARGET class definition.
DLIST_ITERATOR_WRAPPER< TRACK > Tracks()
Definition: class_board.h:254
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp
Module description (excepted pads)
ZONE_CONTAINER * GetArea(int index) const
Function GetArea returns the Area (Zone Container) at a given index.
Definition: class_board.h:997
int GetZoneClearance() const
Definition: class_zone.h:194
EDGE_MODULE class definition.
class DRAWSEGMENT, a segment not on copper layers
Definition: typeinfo.h:91
void SetMaxProgress(int aMaxProgress)
Fix the value thar gives the 100 precent progress bar length (inside the current virtual zone)
void AdvanceProgress()
Increment the progress bar length (inside the current virtual zone)
#define ARC_APPROX_SEGMENTS_COUNT_HIGH_DEF
Definition: pcbnew.h:42
const BOX2I BBox(int aClearance=0) const override
Function BBox()
bool IsOnCopperLayer() const
Function IsOnCopperLayer.
Definition: class_zone.cpp:185
Use thermal relief for pads.
Definition: zones.h:53
DLIST_ITERATOR_WRAPPER< BOARD_ITEM > Drawings()
Definition: class_board.h:256
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
#define min(a, b)
Definition: auxiliary.h:85
pads are covered by copper
Definition: zones.h:54
const SHAPE_POLY_SET & GetFilledPolysList() const
Function GetFilledPolysList returns a reference to the list of filled polygons.
Definition: class_zone.h:566
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)
VECTOR2I B
Definition: seg.h:45
void SetNeedRefill(bool aNeedRefill)
Definition: class_zone.h:192
double GetCircletoPolyCorrectionFactor(int aSegCountforCircle)