KiCad PCB EDA Suite
zones_convert_brd_items_to_polygons_with_Boost.cpp File Reference
#include <cmath>
#include <sstream>
#include <fctsys.h>
#include <wxPcbStruct.h>
#include <trigo.h>
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <class_edge_mod.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <class_zone.h>
#include <project.h>
#include <pcbnew.h>
#include <zones.h>
#include <convert_basic_shapes_to_polygon.h>
#include <geometry/shape_poly_set.h>
#include <geometry/shape_file_io.h>
#include <geometry/convex_hull.h>

Go to the source code of this file.

Macros

#define POLY_CALC_MODE   SHAPE_POLY_SET::PM_FAST
 

Functions

void BuildUnconnectedThermalStubsPolygonList (SHAPE_POLY_SET &aCornerBuffer, BOARD *aPcb, ZONE_CONTAINER *aZone, double aArcCorrection, double aRoundPadThermalRotation)
 Function BuildUnconnectedThermalStubsPolygonList Creates a set of polygons corresponding to stubs created by thermal shapes on pads which are not connected to a zone (dangling bridges) More...
 
void Test_For_Copper_Island_And_Remove (BOARD *aPcb, ZONE_CONTAINER *aZone_container)
 
void CreateThermalReliefPadPolygon (SHAPE_POLY_SET &aCornerBuffer, 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 thickness is min (dx/2, aCopperWitdh) or min (dy/2, aCopperWitdh) More...
 

Variables

static const bool s_DumpZonesWhenFilling = false
 
static double s_thermalRot = 450
 

Macro Definition Documentation

Function Documentation

void BuildUnconnectedThermalStubsPolygonList ( SHAPE_POLY_SET aCornerBuffer,
BOARD aPcb,
ZONE_CONTAINER aZone,
double  aArcCorrection,
double  aRoundPadThermalRotation 
)

Function BuildUnconnectedThermalStubsPolygonList Creates a set of polygons corresponding to stubs created by thermal shapes on pads which are not connected to a zone (dangling bridges)

Parameters
aCornerBuffer= a SHAPE_POLY_SET where to store polygons
aPcb= the board.
aZone= a pointer to the ZONE_CONTAINER to examine.
aArcCorrection= a pointer to the ZONE_CONTAINER to examine.
aRoundPadThermalRotation= the rotation in 1.0 degree for thermal stubs in round pads

Definition at line 88 of file zones_convert_to_polygons_aux_functions.cpp.

References SHAPE_POLY_SET::Append(), BOARD_DESIGN_SETTINGS::GetBiggestClearanceValue(), ZONE_CONTAINER::GetBoundingBox(), BOARD::GetDesignSettings(), BOARD_ITEM::GetLayer(), ZONE_CONTAINER::GetMinThickness(), BOARD_CONNECTED_ITEM::GetNetCode(), ZONE_CONTAINER::GetPadConnection(), ZONE_CONTAINER::GetThermalReliefCopperBridge(), ZONE_CONTAINER::GetThermalReliefGap(), ZONE_CONTAINER::GetZoneClearance(), ZONE_CONTAINER::HitTestFilledArea(), EDA_RECT::Inflate(), EDA_RECT::Intersects(), KiROUND(), BOARD::m_Modules, max, min, SHAPE_POLY_SET::NewOutline(), MODULE::Next(), D_PAD::Next(), PAD_ATTRIB_STANDARD, PAD_SHAPE_CIRCLE, PAD_ZONE_CONN_THERMAL, PAD_ZONE_CONN_THT_THERMAL, RotatePoint(), wxPoint::x, and wxPoint::y.

Referenced by ZONE_CONTAINER::AddClearanceAreasPolygonsToPolysList_NG().

93 {
94  std::vector<wxPoint> corners_buffer; // a local polygon buffer to store one stub
95  corners_buffer.reserve( 4 );
96  wxPoint ptTest[4];
97 
98  int zone_clearance = aZone->GetZoneClearance();
99 
100  EDA_RECT item_boundingbox;
101  EDA_RECT zone_boundingbox = aZone->GetBoundingBox();
102  int biggest_clearance = aPcb->GetDesignSettings().GetBiggestClearanceValue();
103  biggest_clearance = std::max( biggest_clearance, zone_clearance );
104  zone_boundingbox.Inflate( biggest_clearance );
105 
106  // half size of the pen used to draw/plot zones outlines
107  int pen_radius = aZone->GetMinThickness() / 2;
108 
109  for( MODULE* module = aPcb->m_Modules; module; module = module->Next() )
110  {
111  for( D_PAD* pad = module->PadsList(); pad != NULL; pad = pad->Next() )
112  {
113  // Rejects non-standard pads with tht-only thermal reliefs
114  if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
115  && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
116  continue;
117 
118  if( aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
119  && aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
120  continue;
121 
122  // check
123  if( !pad->IsOnLayer( aZone->GetLayer() ) )
124  continue;
125 
126  if( pad->GetNetCode() != aZone->GetNetCode() )
127  continue;
128 
129  // Calculate thermal bridge half width
130  int thermalBridgeWidth = aZone->GetThermalReliefCopperBridge( pad )
131  - aZone->GetMinThickness();
132  if( thermalBridgeWidth <= 0 )
133  continue;
134 
135  // we need the thermal bridge half width
136  // with a small extra size to be sure we create a stub
137  // slightly larger than the actual stub
138  thermalBridgeWidth = ( thermalBridgeWidth + 4 ) / 2;
139 
140  int thermalReliefGap = aZone->GetThermalReliefGap( pad );
141 
142  item_boundingbox = pad->GetBoundingBox();
143  item_boundingbox.Inflate( thermalReliefGap );
144  if( !( item_boundingbox.Intersects( zone_boundingbox ) ) )
145  continue;
146 
147  // Thermal bridges are like a segment from a starting point inside the pad
148  // to an ending point outside the pad
149 
150  // calculate the ending point of the thermal pad, outside the pad
151  wxPoint endpoint;
152  endpoint.x = ( pad->GetSize().x / 2 ) + thermalReliefGap;
153  endpoint.y = ( pad->GetSize().y / 2 ) + thermalReliefGap;
154 
155  // Calculate the starting point of the thermal stub
156  // inside the pad
157  wxPoint startpoint;
158  int copperThickness = aZone->GetThermalReliefCopperBridge( pad )
159  - aZone->GetMinThickness();
160 
161  if( copperThickness < 0 )
162  copperThickness = 0;
163 
164  // Leave a small extra size to the copper area inside to pad
165  copperThickness += KiROUND( IU_PER_MM * 0.04 );
166 
167  startpoint.x = std::min( pad->GetSize().x, copperThickness );
168  startpoint.y = std::min( pad->GetSize().y, copperThickness );
169 
170  startpoint.x /= 2;
171  startpoint.y /= 2;
172 
173  // This is a CIRCLE pad tweak
174  // for circle pads, the thermal stubs orientation is 45 deg
175  double fAngle = pad->GetOrientation();
176  if( pad->GetShape() == PAD_SHAPE_CIRCLE )
177  {
178  endpoint.x = KiROUND( endpoint.x * aArcCorrection );
179  endpoint.y = endpoint.x;
180  fAngle = aRoundPadThermalRotation;
181  }
182 
183  // contour line width has to be taken into calculation to avoid "thermal stub bleed"
184  endpoint.x += pen_radius;
185  endpoint.y += pen_radius;
186  // compute north, south, west and east points for zone connection.
187  ptTest[0] = wxPoint( 0, endpoint.y ); // lower point
188  ptTest[1] = wxPoint( 0, -endpoint.y ); // upper point
189  ptTest[2] = wxPoint( endpoint.x, 0 ); // right point
190  ptTest[3] = wxPoint( -endpoint.x, 0 ); // left point
191 
192  // Test all sides
193  for( int i = 0; i < 4; i++ )
194  {
195  // rotate point
196  RotatePoint( &ptTest[i], fAngle );
197 
198  // translate point
199  ptTest[i] += pad->ShapePos();
200 
201  if( aZone->HitTestFilledArea( ptTest[i] ) )
202  continue;
203 
204  corners_buffer.clear();
205 
206  // polygons are rectangles with width of copper bridge value
207  switch( i )
208  {
209  case 0: // lower stub
210  corners_buffer.push_back( wxPoint( -thermalBridgeWidth, endpoint.y ) );
211  corners_buffer.push_back( wxPoint( +thermalBridgeWidth, endpoint.y ) );
212  corners_buffer.push_back( wxPoint( +thermalBridgeWidth, startpoint.y ) );
213  corners_buffer.push_back( wxPoint( -thermalBridgeWidth, startpoint.y ) );
214  break;
215 
216  case 1: // upper stub
217  corners_buffer.push_back( wxPoint( -thermalBridgeWidth, -endpoint.y ) );
218  corners_buffer.push_back( wxPoint( +thermalBridgeWidth, -endpoint.y ) );
219  corners_buffer.push_back( wxPoint( +thermalBridgeWidth, -startpoint.y ) );
220  corners_buffer.push_back( wxPoint( -thermalBridgeWidth, -startpoint.y ) );
221  break;
222 
223  case 2: // right stub
224  corners_buffer.push_back( wxPoint( endpoint.x, -thermalBridgeWidth ) );
225  corners_buffer.push_back( wxPoint( endpoint.x, thermalBridgeWidth ) );
226  corners_buffer.push_back( wxPoint( +startpoint.x, thermalBridgeWidth ) );
227  corners_buffer.push_back( wxPoint( +startpoint.x, -thermalBridgeWidth ) );
228  break;
229 
230  case 3: // left stub
231  corners_buffer.push_back( wxPoint( -endpoint.x, -thermalBridgeWidth ) );
232  corners_buffer.push_back( wxPoint( -endpoint.x, thermalBridgeWidth ) );
233  corners_buffer.push_back( wxPoint( -startpoint.x, thermalBridgeWidth ) );
234  corners_buffer.push_back( wxPoint( -startpoint.x, -thermalBridgeWidth ) );
235  break;
236  }
237 
238  aCornerBuffer.NewOutline();
239 
240  // add computed polygon to list
241  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
242  {
243  wxPoint cpos = corners_buffer[ic];
244  RotatePoint( &cpos, fAngle ); // Rotate according to module orientation
245  cpos += pad->ShapePos(); // Shift origin to position
246  aCornerBuffer.Append( cpos.x, cpos.y );
247  }
248  }
249  }
250  }
251 }
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
int GetMinThickness() const
Definition: class_zone.h:209
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox (virtual)
Definition: class_zone.cpp:353
int GetBiggestClearanceValue()
Function GetBiggestClearanceValue.
MODULE * Next() const
Definition: class_module.h:100
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
int GetThermalReliefCopperBridge(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:472
ZoneConnection GetPadConnection(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:820
int GetThermalReliefGap(D_PAD *aPad=NULL) const
Definition: class_zone.cpp:463
D_PAD * Next() const
Definition: class_pad.h:145
BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Function GetDesignSettings.
Definition: class_board.h:532
int NewOutline()
Creates a new empty polygon in the set and returns its index
Thermal relief only for THT pads.
Definition: zones.h:60
int GetNetCode() const
Function GetNetCode.
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
#define max(a, b)
Definition: auxiliary.h:86
DLIST< MODULE > m_Modules
Definition: class_board.h:245
bool HitTestFilledArea(const wxPoint &aRefPos) const
Function HitTestFilledArea tests if the given wxPoint is within the bounds of a filled area of this z...
Definition: class_zone.cpp:642
Class EDA_RECT handles the component boundary box.
Usual pad.
Definition: pad_shapes.h:60
Use thermal relief for pads.
Definition: zones.h:58
int GetZoneClearance() const
Definition: class_zone.h:203
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
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 CreateThermalReliefPadPolygon ( SHAPE_POLY_SET aCornerBuffer,
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 thickness is min (dx/2, aCopperWitdh) or min (dy/2, aCopperWitdh)

Parameters
aCornerBuffer= a buffer to store the polygon
aPad= the current pad used to create the thermal shape
aThermalGap= gap in thermal shape
aCopperThickness= stubs thickness in thermal shape
aMinThicknessValue= min copper thickness allowed
aCircleToSegmentsCount= the number of segments to approximate a circle
aCorrectionFactor= the correction to apply to circles radius to keep
aThermalRot= for rond pads the rotation of thermal stubs (450 usually for 45 deg.)

Definition at line 828 of file board_items_to_polygon_shape_transform.cpp.

References AddAngles(), PNS::angle(), SHAPE_POLY_SET::Append(), SHAPE_POLY_SET::BooleanSubtract(), delta, DIM, D_PAD::GetBoundingBox(), EDA_RECT::GetHeight(), D_PAD::GetOrientation(), D_PAD::GetShape(), D_PAD::GetSize(), EDA_RECT::GetWidth(), KiROUND(), max, min, SHAPE_POLY_SET::NewOutline(), PAD_SHAPE_CIRCLE, PAD_SHAPE_OVAL, PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT, PAD_SHAPE_TRAPEZOID, SHAPE_POLY_SET::PM_FAST, SHAPE_POLY_SET::RemoveAllContours(), RotatePoint(), D_PAD::ShapePos(), SHAPE_POLY_SET::Simplify(), D_PAD::TransformShapeWithClearanceToPolygon(), wxPoint::x, and wxPoint::y.

Referenced by ZONE_CONTAINER::buildFeatureHoleList().

836 {
837  wxPoint corner, corner_end;
838  wxPoint padShapePos = aPad.ShapePos(); // Note: for pad having a shape offset,
839  // the pad position is NOT the shape position
840  wxSize copper_thickness;
841 
842  double delta = 3600.0 / aCircleToSegmentsCount; // rot angle in 0.1 degree
843 
844  /* Keep in account the polygon outline thickness
845  * aThermalGap must be increased by aMinThicknessValue/2 because drawing external outline
846  * with a thickness of aMinThicknessValue will reduce gap by aMinThicknessValue/2
847  */
848  aThermalGap += aMinThicknessValue / 2;
849 
850  /* Keep in account the polygon outline thickness
851  * copper_thickness must be decreased by aMinThicknessValue because drawing outlines
852  * with a thickness of aMinThicknessValue will increase real thickness by aMinThicknessValue
853  */
854  aCopperThickness -= aMinThicknessValue;
855 
856  if( aCopperThickness < 0 )
857  aCopperThickness = 0;
858 
859  int dx = aPad.GetSize().x / 2;
860  int dy = aPad.GetSize().y / 2;
861 
862  copper_thickness.x = std::min( dx, aCopperThickness );
863  copper_thickness.y = std::min( dy, aCopperThickness );
864 
865  switch( aPad.GetShape() )
866  {
867  case PAD_SHAPE_CIRCLE: // Add 4 similar holes
868  {
869  /* we create 4 copper holes and put them in position 1, 2, 3 and 4
870  * here is the area of the rectangular pad + its thermal gap
871  * the 4 copper holes remove the copper in order to create the thermal gap
872  * 4 ------ 1
873  * | |
874  * | |
875  * | |
876  * | |
877  * 3 ------ 2
878  * holes 2, 3, 4 are the same as hole 1, rotated 90, 180, 270 deg
879  */
880 
881  // Build the hole pattern, for the hole in the X >0, Y > 0 plane:
882  // The pattern roughtly is a 90 deg arc pie
883  std::vector <wxPoint> corners_buffer;
884 
885  // Radius of outer arcs of the shape corrected for arc approximation by lines
886  int outer_radius = KiROUND( (dx + aThermalGap) * aCorrectionFactor );
887 
888  // Crosspoint of thermal spoke sides, the first point of polygon buffer
889  corners_buffer.push_back( wxPoint( copper_thickness.x / 2, copper_thickness.y / 2 ) );
890 
891  // Add an intermediate point on spoke sides, to allow a > 90 deg angle between side
892  // and first seg of arc approx
893  corner.x = copper_thickness.x / 2;
894  int y = outer_radius - (aThermalGap / 4);
895  corner.y = KiROUND( sqrt( ( (double) y * y - (double) corner.x * corner.x ) ) );
896 
897  if( aThermalRot != 0 )
898  corners_buffer.push_back( corner );
899 
900  // calculate the starting point of the outter arc
901  corner.x = copper_thickness.x / 2;
902 
903  corner.y = KiROUND( sqrt( ( (double) outer_radius * outer_radius ) -
904  ( (double) corner.x * corner.x ) ) );
905  RotatePoint( &corner, 90 ); // 9 degrees is the spoke fillet size
906 
907  // calculate the ending point of the outter arc
908  corner_end.x = corner.y;
909  corner_end.y = corner.x;
910 
911  // calculate intermediate points (y coordinate from corner.y to corner_end.y
912  while( (corner.y > corner_end.y) && (corner.x < corner_end.x) )
913  {
914  corners_buffer.push_back( corner );
915  RotatePoint( &corner, delta );
916  }
917 
918  corners_buffer.push_back( corner_end );
919 
920  /* add an intermediate point, to avoid angles < 90 deg between last arc approx line
921  * and radius line
922  */
923  corner.x = corners_buffer[1].y;
924  corner.y = corners_buffer[1].x;
925  corners_buffer.push_back( corner );
926 
927  // Now, add the 4 holes ( each is the pattern, rotated by 0, 90, 180 and 270 deg
928  // aThermalRot = 450 (45.0 degrees orientation) work fine.
929  double angle_pad = aPad.GetOrientation(); // Pad orientation
930  double th_angle = aThermalRot;
931 
932  for( unsigned ihole = 0; ihole < 4; ihole++ )
933  {
934  aCornerBuffer.NewOutline();
935 
936  for( unsigned ii = 0; ii < corners_buffer.size(); ii++ )
937  {
938  corner = corners_buffer[ii];
939  RotatePoint( &corner, th_angle + angle_pad ); // Rotate by segment angle and pad orientation
940  corner += padShapePos;
941  aCornerBuffer.Append( corner.x, corner.y );
942  }
943 
944  th_angle += 900; // Note: th_angle in in 0.1 deg.
945  }
946  }
947  break;
948 
949  case PAD_SHAPE_OVAL:
950  {
951  // Oval pad support along the lines of round and rectangular pads
952  std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
953 
954  dx = (aPad.GetSize().x / 2) + aThermalGap; // Cutout radius x
955  dy = (aPad.GetSize().y / 2) + aThermalGap; // Cutout radius y
956 
957  wxPoint shape_offset;
958 
959  // We want to calculate an oval shape with dx > dy.
960  // if this is not the case, exchange dx and dy, and rotate the shape 90 deg.
961  int supp_angle = 0;
962 
963  if( dx < dy )
964  {
965  std::swap( dx, dy );
966  supp_angle = 900;
967  std::swap( copper_thickness.x, copper_thickness.y );
968  }
969 
970  int deltasize = dx - dy; // = distance between shape position and the 2 demi-circle ends centre
971  // here we have dx > dy
972  // Radius of outer arcs of the shape:
973  int outer_radius = dy; // The radius of the outer arc is radius end + aThermalGap
974 
975  // Some coordinate fiddling, depending on the shape offset direction
976  shape_offset = wxPoint( deltasize, 0 );
977 
978  // Crosspoint of thermal spoke sides, the first point of polygon buffer
979  corner.x = copper_thickness.x / 2;
980  corner.y = copper_thickness.y / 2;
981  corners_buffer.push_back( corner );
982 
983  // Arc start point calculation, the intersecting point of cutout arc and thermal spoke edge
984  // If copper thickness is more than shape offset, we need to calculate arc intercept point.
985  if( copper_thickness.x > deltasize )
986  {
987  corner.x = copper_thickness.x / 2;
988  corner.y = KiROUND( sqrt( ( (double) outer_radius * outer_radius ) -
989  ( (double) ( corner.x - delta ) * ( corner.x - deltasize ) ) ) );
990  corner.x -= deltasize;
991 
992  /* creates an intermediate point, to have a > 90 deg angle
993  * between the side and the first segment of arc approximation
994  */
995  wxPoint intpoint = corner;
996  intpoint.y -= aThermalGap / 4;
997  corners_buffer.push_back( intpoint + shape_offset );
998  RotatePoint( &corner, 90 ); // 9 degrees of thermal fillet
999  }
1000  else
1001  {
1002  corner.x = copper_thickness.x / 2;
1003  corner.y = outer_radius;
1004  corners_buffer.push_back( corner );
1005  }
1006 
1007  // Add an intermediate point on spoke sides, to allow a > 90 deg angle between side
1008  // and first seg of arc approx
1009  wxPoint last_corner;
1010  last_corner.y = copper_thickness.y / 2;
1011  int px = outer_radius - (aThermalGap / 4);
1012  last_corner.x =
1013  KiROUND( sqrt( ( ( (double) px * px ) - (double) last_corner.y * last_corner.y ) ) );
1014 
1015  // Arc stop point calculation, the intersecting point of cutout arc and thermal spoke edge
1016  corner_end.y = copper_thickness.y / 2;
1017  corner_end.x =
1018  KiROUND( sqrt( ( (double) outer_radius *
1019  outer_radius ) - ( (double) corner_end.y * corner_end.y ) ) );
1020  RotatePoint( &corner_end, -90 ); // 9 degrees of thermal fillet
1021 
1022  // calculate intermediate arc points till limit is reached
1023  while( (corner.y > corner_end.y) && (corner.x < corner_end.x) )
1024  {
1025  corners_buffer.push_back( corner + shape_offset );
1026  RotatePoint( &corner, delta );
1027  }
1028 
1029  //corners_buffer.push_back(corner + shape_offset); // TODO: about one mil geometry error forms somewhere.
1030  corners_buffer.push_back( corner_end + shape_offset );
1031  corners_buffer.push_back( last_corner + shape_offset ); // Enabling the line above shows intersection point.
1032 
1033  /* Create 2 holes, rotated by pad rotation.
1034  */
1035  double angle = aPad.GetOrientation() + supp_angle;
1036 
1037  for( int irect = 0; irect < 2; irect++ )
1038  {
1039  aCornerBuffer.NewOutline();
1040  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1041  {
1042  wxPoint cpos = corners_buffer[ic];
1043  RotatePoint( &cpos, angle );
1044  cpos += padShapePos;
1045  aCornerBuffer.Append( cpos.x, cpos.y );
1046  }
1047 
1048  angle = AddAngles( angle, 1800 ); // this is calculate hole 3
1049  }
1050 
1051  // Create holes, that are the mirrored from the previous holes
1052  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1053  {
1054  wxPoint swap = corners_buffer[ic];
1055  swap.x = -swap.x;
1056  corners_buffer[ic] = swap;
1057  }
1058 
1059  // Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
1060  angle = aPad.GetOrientation() + supp_angle;
1061 
1062  for( int irect = 0; irect < 2; irect++ )
1063  {
1064  aCornerBuffer.NewOutline();
1065 
1066  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1067  {
1068  wxPoint cpos = corners_buffer[ic];
1069  RotatePoint( &cpos, angle );
1070  cpos += padShapePos;
1071  aCornerBuffer.Append( cpos.x, cpos.y );
1072  }
1073 
1074  angle = AddAngles( angle, 1800 );
1075  }
1076  }
1077  break;
1078 
1079  case PAD_SHAPE_ROUNDRECT: // thermal shape is the same for round rect and rect.
1080  case PAD_SHAPE_RECT:
1081  {
1082  /* we create 4 copper holes and put them in position 1, 2, 3 and 4
1083  * here is the area of the rectangular pad + its thermal gap
1084  * the 4 copper holes remove the copper in order to create the thermal gap
1085  * 4 ------ 1
1086  * | |
1087  * | |
1088  * | |
1089  * | |
1090  * 3 ------ 2
1091  * hole 3 is the same as hole 1, rotated 180 deg
1092  * hole 4 is the same as hole 2, rotated 180 deg and is the same as hole 1, mirrored
1093  */
1094 
1095  // First, create a rectangular hole for position 1 :
1096  // 2 ------- 3
1097  // | |
1098  // | |
1099  // | |
1100  // 1 -------4
1101 
1102  // Modified rectangles with one corner rounded. TODO: merging with oval thermals
1103  // and possibly round too.
1104 
1105  std::vector <wxPoint> corners_buffer; // Polygon buffer as vector
1106 
1107  dx = (aPad.GetSize().x / 2) + aThermalGap; // Cutout radius x
1108  dy = (aPad.GetSize().y / 2) + aThermalGap; // Cutout radius y
1109 
1110  // The first point of polygon buffer is left lower corner, second the crosspoint of
1111  // thermal spoke sides, the third is upper right corner and the rest are rounding
1112  // vertices going anticlockwise. Note the inveted Y-axis in CG.
1113  corners_buffer.push_back( wxPoint( -dx, -(aThermalGap / 4 + copper_thickness.y / 2) ) ); // Adds small miters to zone
1114  corners_buffer.push_back( wxPoint( -(dx - aThermalGap / 4), -copper_thickness.y / 2 ) ); // fill and spoke corner
1115  corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -copper_thickness.y / 2 ) );
1116  corners_buffer.push_back( wxPoint( -copper_thickness.x / 2, -(dy - aThermalGap / 4) ) );
1117  corners_buffer.push_back( wxPoint( -(aThermalGap / 4 + copper_thickness.x / 2), -dy ) );
1118 
1119  double angle = aPad.GetOrientation();
1120  int rounding_radius = KiROUND( aThermalGap * aCorrectionFactor ); // Corner rounding radius
1121 
1122  for( int i = 0; i < aCircleToSegmentsCount / 4 + 1; i++ )
1123  {
1124  wxPoint corner_position = wxPoint( 0, -rounding_radius );
1125 
1126  // Start at half increment offset
1127  RotatePoint( &corner_position, 1800.0 / aCircleToSegmentsCount );
1128  double angle_pg = i * delta;
1129 
1130  RotatePoint( &corner_position, angle_pg ); // Rounding vector rotation
1131  corner_position -= aPad.GetSize() / 2; // Rounding vector + Pad corner offset
1132 
1133  corners_buffer.push_back( wxPoint( corner_position.x, corner_position.y ) );
1134  }
1135 
1136  for( int irect = 0; irect < 2; irect++ )
1137  {
1138  aCornerBuffer.NewOutline();
1139 
1140  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1141  {
1142  wxPoint cpos = corners_buffer[ic];
1143  RotatePoint( &cpos, angle ); // Rotate according to module orientation
1144  cpos += padShapePos; // Shift origin to position
1145  aCornerBuffer.Append( cpos.x, cpos.y );
1146  }
1147 
1148  angle = AddAngles( angle, 1800 ); // this is calculate hole 3
1149  }
1150 
1151  // Create holes, that are the mirrored from the previous holes
1152  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1153  {
1154  wxPoint swap = corners_buffer[ic];
1155  swap.x = -swap.x;
1156  corners_buffer[ic] = swap;
1157  }
1158 
1159  // Now add corner 4 and 2 (2 is the corner 4 rotated by 180 deg
1160  for( int irect = 0; irect < 2; irect++ )
1161  {
1162  aCornerBuffer.NewOutline();
1163 
1164  for( unsigned ic = 0; ic < corners_buffer.size(); ic++ )
1165  {
1166  wxPoint cpos = corners_buffer[ic];
1167  RotatePoint( &cpos, angle );
1168  cpos += padShapePos;
1169  aCornerBuffer.Append( cpos.x, cpos.y );
1170  }
1171 
1172  angle = AddAngles( angle, 1800 );
1173  }
1174  }
1175  break;
1176 
1177  case PAD_SHAPE_TRAPEZOID:
1178  {
1179  SHAPE_POLY_SET antipad; // The full antipad area
1180 
1181  // We need a length to build the stubs of the thermal reliefs
1182  // the value is not very important. The pad bounding box gives a reasonable value
1183  EDA_RECT bbox = aPad.GetBoundingBox();
1184  int stub_len = std::max( bbox.GetWidth(), bbox.GetHeight() );
1185 
1186  aPad.TransformShapeWithClearanceToPolygon( antipad, aThermalGap,
1187  aCircleToSegmentsCount, aCorrectionFactor );
1188 
1189  SHAPE_POLY_SET stub; // A basic stub ( a rectangle)
1190  SHAPE_POLY_SET stubs; // the full stubs shape
1191 
1192 
1193  // We now substract the stubs (connections to the copper zone)
1194  //ClipperLib::Clipper clip_engine;
1195  // Prepare a clipping transform
1196  //clip_engine.AddPath( antipad, ClipperLib::ptSubject, true );
1197 
1198  // Create stubs and add them to clipper engine
1199  wxPoint stubBuffer[4];
1200  stubBuffer[0].x = stub_len;
1201  stubBuffer[0].y = copper_thickness.y/2;
1202  stubBuffer[1] = stubBuffer[0];
1203  stubBuffer[1].y = -copper_thickness.y/2;
1204  stubBuffer[2] = stubBuffer[1];
1205  stubBuffer[2].x = -stub_len;
1206  stubBuffer[3] = stubBuffer[2];
1207  stubBuffer[3].y = copper_thickness.y/2;
1208 
1209  stub.NewOutline();
1210 
1211  for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
1212  {
1213  wxPoint cpos = stubBuffer[ii];
1214  RotatePoint( &cpos, aPad.GetOrientation() );
1215  cpos += padShapePos;
1216  stub.Append( cpos.x, cpos.y );
1217  }
1218 
1219  stubs.Append( stub );
1220 
1221  stubBuffer[0].y = stub_len;
1222  stubBuffer[0].x = copper_thickness.x/2;
1223  stubBuffer[1] = stubBuffer[0];
1224  stubBuffer[1].x = -copper_thickness.x/2;
1225  stubBuffer[2] = stubBuffer[1];
1226  stubBuffer[2].y = -stub_len;
1227  stubBuffer[3] = stubBuffer[2];
1228  stubBuffer[3].x = copper_thickness.x/2;
1229 
1230  stub.RemoveAllContours();
1231  stub.NewOutline();
1232 
1233  for( unsigned ii = 0; ii < DIM( stubBuffer ); ii++ )
1234  {
1235  wxPoint cpos = stubBuffer[ii];
1236  RotatePoint( &cpos, aPad.GetOrientation() );
1237  cpos += padShapePos;
1238  stub.Append( cpos.x, cpos.y );
1239  }
1240 
1241  stubs.Append( stub );
1243 
1244  antipad.BooleanSubtract( stubs, SHAPE_POLY_SET::PM_FAST );
1245  aCornerBuffer.Append( antipad );
1246 
1247  break;
1248  }
1249 
1250  default:
1251  ;
1252  }
1253 }
#define DIM(x)
of elements in an array
Definition: macros.h:98
static int KiROUND(double v)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
int GetHeight() const
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:317
PAD_SHAPE_T GetShape() const
Function GetShape.
Definition: class_pad.h:201
static const int delta[8][2]
Definition: solve.cpp:112
void TransformShapeWithClearanceToPolygon(SHAPE_POLY_SET &aCornerBuffer, int aClearanceValue, int aCircleToSegmentsCount, double aCorrectionFactor) const
Function TransformShapeWithClearanceToPolygon Convert the pad shape to a closed polygon Used in filli...
T AddAngles(T a1, T2 a2)
Add two angles (keeping the result normalized). T2 is here.
Definition: trigo.h:246
Class SHAPE_POLY_SET.
const wxSize & GetSize() const
Definition: class_pad.h:254
void Simplify(POLYGON_MODE aFastMode)
Simplifies the polyset (merges overlapping polys, eliminates degeneracy/self-intersections) For aFast...
int NewOutline()
Creates a new empty polygon in the set and returns its index
#define max(a, b)
Definition: auxiliary.h:86
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
void RemoveAllContours()
Removes all outlines & holes (clears) the polygon set.
double GetOrientation() const
Function GetOrientation returns the rotation angle of the pad in tenths of degrees, but soon degrees.
Definition: class_pad.h:357
Class EDA_RECT handles the component boundary box.
int GetWidth() const
wxPoint ShapePos() const
Definition: class_pad.cpp:500
void BooleanSubtract(const SHAPE_POLY_SET &b, POLYGON_MODE aFastMode)
Performs boolean polyset difference For aFastMode meaning, see function booleanOp ...
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
Definition: class_pad.cpp:199
#define min(a, b)
Definition: auxiliary.h:85
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 Test_For_Copper_Island_And_Remove ( BOARD aPcb,
ZONE_CONTAINER aZone_container 
)

Variable Documentation

const bool s_DumpZonesWhenFilling = false
static