KiCad PCB EDA Suite
board_items_to_polygon_shape_transform.cpp File Reference
#include <vector>
#include <fctsys.h>
#include <drawtxt.h>
#include <pcbnew.h>
#include <wxPcbStruct.h>
#include <trigo.h>
#include <class_board.h>
#include <class_pad.h>
#include <class_track.h>
#include <class_drawsegment.h>
#include <class_pcb_text.h>
#include <class_zone.h>
#include <class_module.h>
#include <class_edge_mod.h>
#include <convert_basic_shapes_to_polygon.h>

Go to the source code of this file.

Functions

static void addTextSegmToPoly (int x0, int y0, int xf, int yf)
 
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 int s_textWidth
 
static int s_textCircle2SegmentCount
 
static SHAPE_POLY_SETs_cornerBuffer
 

Function Documentation

static void addTextSegmToPoly ( int  x0,
int  y0,
int  xf,
int  yf 
)
static

Definition at line 58 of file board_items_to_polygon_shape_transform.cpp.

References s_textCircle2SegmentCount, s_textWidth, and TransformRoundedEndsSegmentToPolygon().

Referenced by MODULE::TransformGraphicShapesWithClearanceToPolygonSet(), MODULE::TransformGraphicTextWithClearanceToPolygonSet(), and TEXTE_PCB::TransformShapeWithClearanceToPolygonSet().

59 {
61  wxPoint( x0, y0), wxPoint( xf, yf ),
63 }
void TransformRoundedEndsSegmentToPolygon(SHAPE_POLY_SET &aCornerBuffer, wxPoint aStart, wxPoint aEnd, int aCircleToSegmentsCount, int aWidth)
Function TransformRoundedEndsSegmentToPolygon convert a segment with rounded ends to a polygon Conver...
static SHAPE_POLY_SET * s_cornerBuffer
static int s_textCircle2SegmentCount
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 815 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().

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

Variable Documentation

SHAPE_POLY_SET* s_cornerBuffer
static

Definition at line 55 of file board_items_to_polygon_shape_transform.cpp.