You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

680 lines
23 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2009-2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. #include <fctsys.h>
  25. #include <vector>
  26. #include <bezier_curves.h>
  27. #include <base_units.h> // for IU_PER_MM
  28. #include <gr_text.h>
  29. #include <pcbnew.h>
  30. #include <pcb_edit_frame.h>
  31. #include <trigo.h>
  32. #include <class_board.h>
  33. #include <class_pad.h>
  34. #include <class_track.h>
  35. #include <class_drawsegment.h>
  36. #include <class_pcb_text.h>
  37. #include <class_zone.h>
  38. #include <class_module.h>
  39. #include <class_edge_mod.h>
  40. #include <convert_basic_shapes_to_polygon.h>
  41. #include <geometry/geometry_utils.h>
  42. #include <geometry/shape_segment.h>
  43. #include <math/util.h> // for KiROUND
  44. // A helper struct for the callback function
  45. // These variables are parameters used in addTextSegmToPoly.
  46. // But addTextSegmToPoly is a call-back function,
  47. // so we cannot send them as arguments.
  48. struct TSEGM_2_POLY_PRMS {
  49. int m_textWidth;
  50. int m_error;
  51. SHAPE_POLY_SET* m_cornerBuffer;
  52. };
  53. TSEGM_2_POLY_PRMS prms;
  54. // This is a call back function, used by GRText to draw the 3D text shape:
  55. static void addTextSegmToPoly( int x0, int y0, int xf, int yf, void* aData )
  56. {
  57. TSEGM_2_POLY_PRMS* prm = static_cast<TSEGM_2_POLY_PRMS*>( aData );
  58. TransformSegmentToPolygon( *prm->m_cornerBuffer,
  59. wxPoint( x0, y0 ), wxPoint( xf, yf ),
  60. prm->m_error, prm->m_textWidth );
  61. }
  62. void BOARD::ConvertBrdLayerToPolygonalContours( PCB_LAYER_ID aLayer, SHAPE_POLY_SET& aOutlines )
  63. {
  64. // convert tracks and vias:
  65. for( auto track : m_tracks )
  66. {
  67. if( !track->IsOnLayer( aLayer ) )
  68. continue;
  69. track->TransformShapeWithClearanceToPolygon( aOutlines, aLayer, 0 );
  70. }
  71. // convert pads
  72. for( auto module : m_modules )
  73. {
  74. module->TransformPadsShapesWithClearanceToPolygon( aLayer, aOutlines, 0 );
  75. // Micro-wave modules may have items on copper layers
  76. module->TransformGraphicShapesWithClearanceToPolygonSet( aLayer, aOutlines, 0 );
  77. }
  78. // convert copper zones
  79. for( int ii = 0; ii < GetAreaCount(); ii++ )
  80. {
  81. ZONE_CONTAINER* zone = GetArea( ii );
  82. if( zone->GetLayerSet().test( aLayer ) )
  83. zone->TransformSolidAreasShapesToPolygon( aLayer, aOutlines );
  84. }
  85. // convert graphic items on copper layers (texts)
  86. for( auto item : m_drawings )
  87. {
  88. if( !item->IsOnLayer( aLayer ) )
  89. continue;
  90. switch( item->Type() )
  91. {
  92. case PCB_LINE_T:
  93. ( (DRAWSEGMENT*) item )->TransformShapeWithClearanceToPolygon( aOutlines, aLayer, 0 );
  94. break;
  95. case PCB_TEXT_T:
  96. ( (TEXTE_PCB*) item )->TransformShapeWithClearanceToPolygonSet( aOutlines, 0 );
  97. break;
  98. default:
  99. break;
  100. }
  101. }
  102. }
  103. void MODULE::TransformPadsShapesWithClearanceToPolygon( PCB_LAYER_ID aLayer,
  104. SHAPE_POLY_SET& aCornerBuffer, int aInflateValue, int aMaxError,
  105. bool aSkipNPTHPadsWihNoCopper ) const
  106. {
  107. for( D_PAD* pad : m_pads )
  108. {
  109. if( aLayer != UNDEFINED_LAYER && !pad->IsOnLayer(aLayer) )
  110. continue;
  111. if( !pad->IsPadOnLayer( aLayer ) && IsCopperLayer( aLayer ) )
  112. continue;
  113. // NPTH pads are not drawn on layers if the shape size and pos is the same
  114. // as their hole:
  115. if( aSkipNPTHPadsWihNoCopper && pad->GetAttribute() == PAD_ATTRIB_HOLE_NOT_PLATED )
  116. {
  117. if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == wxPoint( 0, 0 ) )
  118. {
  119. switch( pad->GetShape() )
  120. {
  121. case PAD_SHAPE_CIRCLE:
  122. if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
  123. continue;
  124. break;
  125. case PAD_SHAPE_OVAL:
  126. if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
  127. continue;
  128. break;
  129. default:
  130. break;
  131. }
  132. }
  133. }
  134. wxSize margin;
  135. int clearance = aInflateValue;
  136. switch( aLayer )
  137. {
  138. case F_Mask:
  139. case B_Mask:
  140. clearance += pad->GetSolderMaskMargin();
  141. break;
  142. case F_Paste:
  143. case B_Paste:
  144. margin = pad->GetSolderPasteMargin();
  145. clearance += ( margin.x + margin.y ) / 2;
  146. break;
  147. default:
  148. break;
  149. }
  150. pad->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, clearance );
  151. }
  152. }
  153. /**
  154. * Generate shapes of graphic items (outlines) as polygons added to a buffer.
  155. * @aCornerBuffer = the buffer to store polygons
  156. * @aInflateValue = a value to inflate shapes
  157. * @aError = the maximum error to allow when approximating curves with segments
  158. * @aIncludeText = indicates footprint text items (reference, value, etc.) should be included
  159. * in the outline
  160. */
  161. void MODULE::TransformGraphicShapesWithClearanceToPolygonSet( PCB_LAYER_ID aLayer,
  162. SHAPE_POLY_SET& aCornerBuffer,
  163. int aInflateValue,
  164. int aError,
  165. bool aIncludeText,
  166. bool aIncludeEdges ) const
  167. {
  168. std::vector<TEXTE_MODULE *> texts; // List of TEXTE_MODULE to convert
  169. for( auto item : GraphicalItems() )
  170. {
  171. if( item->Type() == PCB_MODULE_TEXT_T && aIncludeText )
  172. {
  173. TEXTE_MODULE* text = static_cast<TEXTE_MODULE*>( item );
  174. if( aLayer != UNDEFINED_LAYER && text->GetLayer() == aLayer && text->IsVisible() )
  175. texts.push_back( text );
  176. }
  177. if( item->Type() == PCB_MODULE_EDGE_T && aIncludeEdges )
  178. {
  179. EDGE_MODULE* outline = (EDGE_MODULE*) item;
  180. if( aLayer != UNDEFINED_LAYER && outline->GetLayer() == aLayer )
  181. outline->TransformShapeWithClearanceToPolygon( aCornerBuffer, aLayer, 0, aError );
  182. }
  183. }
  184. if( aIncludeText )
  185. {
  186. if( Reference().GetLayer() == aLayer && Reference().IsVisible() )
  187. texts.push_back( &Reference() );
  188. if( Value().GetLayer() == aLayer && Value().IsVisible() )
  189. texts.push_back( &Value() );
  190. }
  191. prms.m_cornerBuffer = &aCornerBuffer;
  192. for( TEXTE_MODULE* textmod : texts )
  193. {
  194. bool forceBold = true;
  195. int penWidth = 0; // force max width for bold text
  196. prms.m_textWidth = textmod->GetEffectiveTextPenWidth() + ( 2 * aInflateValue );
  197. prms.m_error = aError;
  198. wxSize size = textmod->GetTextSize();
  199. if( textmod->IsMirrored() )
  200. size.x = -size.x;
  201. GRText( NULL, textmod->GetTextPos(), BLACK, textmod->GetShownText(),
  202. textmod->GetDrawRotation(), size, textmod->GetHorizJustify(),
  203. textmod->GetVertJustify(), penWidth, textmod->IsItalic(), forceBold,
  204. addTextSegmToPoly, &prms );
  205. }
  206. }
  207. void ZONE_CONTAINER::TransformSolidAreasShapesToPolygon( PCB_LAYER_ID aLayer,
  208. SHAPE_POLY_SET& aCornerBuffer,
  209. int aError ) const
  210. {
  211. if( !m_FilledPolysList.count( aLayer ) || m_FilledPolysList.at( aLayer ).IsEmpty() )
  212. return;
  213. // Just add filled areas if filled polygons outlines have no thickness
  214. if( !GetFilledPolysUseThickness() || GetMinThickness() == 0 )
  215. {
  216. const SHAPE_POLY_SET& polys = m_FilledPolysList.at( aLayer );
  217. aCornerBuffer.Append( polys );
  218. return;
  219. }
  220. // Filled areas have polygons with outline thickness.
  221. // we must create the polygons and add inflated polys
  222. SHAPE_POLY_SET polys = m_FilledPolysList.at( aLayer );
  223. auto board = GetBoard();
  224. int maxError = ARC_HIGH_DEF;
  225. if( board )
  226. maxError = board->GetDesignSettings().m_MaxError;
  227. int numSegs = std::max( GetArcToSegmentCount( GetMinThickness(), maxError, 360.0 ), 12 );
  228. polys.InflateWithLinkedHoles( GetMinThickness()/2, numSegs, SHAPE_POLY_SET::PM_FAST );
  229. aCornerBuffer.Append( polys );
  230. }
  231. void EDA_TEXT::TransformBoundingBoxWithClearanceToPolygon( SHAPE_POLY_SET* aCornerBuffer,
  232. int aClearanceValue ) const
  233. {
  234. if( GetText().Length() == 0 )
  235. return;
  236. wxPoint corners[4]; // Buffer of polygon corners
  237. EDA_RECT rect = GetTextBox();
  238. rect.Inflate( aClearanceValue + Millimeter2iu( DEFAULT_TEXT_WIDTH ) );
  239. corners[0].x = rect.GetOrigin().x;
  240. corners[0].y = rect.GetOrigin().y;
  241. corners[1].y = corners[0].y;
  242. corners[1].x = rect.GetRight();
  243. corners[2].x = corners[1].x;
  244. corners[2].y = rect.GetBottom();
  245. corners[3].y = corners[2].y;
  246. corners[3].x = corners[0].x;
  247. aCornerBuffer->NewOutline();
  248. for( wxPoint& corner : corners )
  249. {
  250. // Rotate polygon
  251. RotatePoint( &corner.x, &corner.y, GetTextPos().x, GetTextPos().y, GetTextAngle() );
  252. aCornerBuffer->Append( corner.x, corner.y );
  253. }
  254. }
  255. /**
  256. * Function TransformShapeWithClearanceToPolygonSet
  257. * Convert the text shape to a set of polygons (one per segment).
  258. * @aCornerBuffer = SHAPE_POLY_SET to store the polygon corners
  259. * @aClearanceValue = the clearance around the text
  260. * @aError = the maximum error to allow when approximating curves
  261. */
  262. void TEXTE_PCB::TransformShapeWithClearanceToPolygonSet( SHAPE_POLY_SET& aCornerBuffer,
  263. int aClearanceValue, int aError ) const
  264. {
  265. wxSize size = GetTextSize();
  266. if( IsMirrored() )
  267. size.x = -size.x;
  268. bool forceBold = true;
  269. int penWidth = GetEffectiveTextPenWidth();
  270. prms.m_cornerBuffer = &aCornerBuffer;
  271. prms.m_textWidth = GetEffectiveTextPenWidth() + ( 2 * aClearanceValue );
  272. prms.m_error = aError;
  273. COLOR4D color = COLOR4D::BLACK; // not actually used, but needed by GRText
  274. if( IsMultilineAllowed() )
  275. {
  276. wxArrayString strings_list;
  277. wxStringSplit( GetShownText(), strings_list, '\n' );
  278. std::vector<wxPoint> positions;
  279. positions.reserve( strings_list.Count() );
  280. GetLinePositions( positions, strings_list.Count() );
  281. for( unsigned ii = 0; ii < strings_list.Count(); ii++ )
  282. {
  283. wxString txt = strings_list.Item( ii );
  284. GRText( NULL, positions[ii], color, txt, GetTextAngle(), size, GetHorizJustify(),
  285. GetVertJustify(), penWidth, IsItalic(), forceBold, addTextSegmToPoly, &prms );
  286. }
  287. }
  288. else
  289. {
  290. GRText( NULL, GetTextPos(), color, GetShownText(), GetTextAngle(), size, GetHorizJustify(),
  291. GetVertJustify(), penWidth, IsItalic(), forceBold, addTextSegmToPoly, &prms );
  292. }
  293. }
  294. void DRAWSEGMENT::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
  295. PCB_LAYER_ID aLayer,
  296. int aClearanceValue, int aError,
  297. bool ignoreLineWidth ) const
  298. {
  299. int width = ignoreLineWidth ? 0 : m_Width;
  300. width += 2 * aClearanceValue;
  301. // Creating a reliable clearance shape for circles and arcs is not so easy, due to
  302. // the error created by segment approximation.
  303. // for a circle this is not so hard: create a polygon from a circle slightly bigger:
  304. // thickness = width + s_error_max, and radius = initial radius + s_error_max/2
  305. // giving a shape with a suitable internal radius and external radius
  306. // For an arc this is more tricky: TODO
  307. switch( m_Shape )
  308. {
  309. case S_CIRCLE:
  310. if( width == 0 )
  311. TransformCircleToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError );
  312. else
  313. TransformRingToPolygon( aCornerBuffer, GetCenter(), GetRadius(), aError, width );
  314. break;
  315. case S_RECT:
  316. {
  317. std::vector<wxPoint> pts;
  318. GetRectCorners( &pts );
  319. if( width == 0 )
  320. {
  321. aCornerBuffer.NewOutline();
  322. for( const wxPoint& pt : pts )
  323. aCornerBuffer.Append( pt );
  324. }
  325. if( width > 0 )
  326. {
  327. // Add in segments
  328. TransformSegmentToPolygon( aCornerBuffer, pts[0], pts[1], aError, width );
  329. TransformSegmentToPolygon( aCornerBuffer, pts[1], pts[2], aError, width );
  330. TransformSegmentToPolygon( aCornerBuffer, pts[2], pts[3], aError, width );
  331. TransformSegmentToPolygon( aCornerBuffer, pts[3], pts[0], aError, width );
  332. }
  333. }
  334. break;
  335. case S_ARC:
  336. TransformArcToPolygon( aCornerBuffer, GetCenter(), GetArcStart(), m_Angle, aError, width );
  337. break;
  338. case S_SEGMENT:
  339. TransformOvalToPolygon( aCornerBuffer, m_Start, m_End, width, aError );
  340. break;
  341. case S_POLYGON:
  342. if( IsPolyShapeValid() )
  343. {
  344. // The polygon is expected to be a simple polygon
  345. // not self intersecting, no hole.
  346. MODULE* module = GetParentModule(); // NULL for items not in footprints
  347. double orientation = module ? module->GetOrientation() : 0.0;
  348. wxPoint offset;
  349. if( module )
  350. offset = module->GetPosition();
  351. // Build the polygon with the actual position and orientation:
  352. std::vector< wxPoint> poly;
  353. poly = BuildPolyPointsList();
  354. for( wxPoint& point : poly )
  355. {
  356. RotatePoint( &point, orientation );
  357. point += offset;
  358. }
  359. if( IsPolygonFilled() || width == 0 )
  360. {
  361. aCornerBuffer.NewOutline();
  362. for( wxPoint& point : poly )
  363. aCornerBuffer.Append( point.x, point.y );
  364. }
  365. if( width > 0 )
  366. {
  367. wxPoint pt1( poly[ poly.size() - 1] );
  368. for( wxPoint pt2 : poly )
  369. {
  370. if( pt2 != pt1 )
  371. TransformSegmentToPolygon( aCornerBuffer, pt1, pt2, aError, width );
  372. pt1 = pt2;
  373. }
  374. }
  375. }
  376. break;
  377. case S_CURVE: // Bezier curve
  378. {
  379. std::vector<wxPoint> ctrlPoints = { m_Start, m_BezierC1, m_BezierC2, m_End };
  380. BEZIER_POLY converter( ctrlPoints );
  381. std::vector< wxPoint> poly;
  382. converter.GetPoly( poly, m_Width );
  383. if( width != 0 )
  384. {
  385. for( unsigned ii = 1; ii < poly.size(); ii++ )
  386. TransformSegmentToPolygon( aCornerBuffer, poly[ii-1], poly[ii], aError, width );
  387. }
  388. }
  389. break;
  390. default:
  391. wxFAIL_MSG( "DRAWSEGMENT::TransformShapeWithClearanceToPolygon no implementation for "
  392. + STROKE_T_asString( m_Shape ) );
  393. break;
  394. }
  395. }
  396. void TRACK::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
  397. PCB_LAYER_ID aLayer,
  398. int aClearanceValue, int aError,
  399. bool ignoreLineWidth ) const
  400. {
  401. wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for tracks." );
  402. int width = m_Width + ( 2 * aClearanceValue );
  403. switch( Type() )
  404. {
  405. case PCB_VIA_T:
  406. {
  407. int radius = ( m_Width / 2 ) + aClearanceValue;
  408. TransformCircleToPolygon( aCornerBuffer, m_Start, radius, aError );
  409. }
  410. break;
  411. case PCB_ARC_T:
  412. {
  413. const ARC* arc = static_cast<const ARC*>( this );
  414. VECTOR2D center( arc->GetCenter() );
  415. double arc_angle = arc->GetAngle();
  416. TransformArcToPolygon( aCornerBuffer, wxPoint( center.x, center.y ),
  417. GetStart(), arc_angle, aError, width );
  418. }
  419. break;
  420. default:
  421. TransformOvalToPolygon( aCornerBuffer, m_Start, m_End, width, aError );
  422. break;
  423. }
  424. }
  425. void D_PAD::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
  426. PCB_LAYER_ID aLayer,
  427. int aClearanceValue, int aError,
  428. bool ignoreLineWidth ) const
  429. {
  430. wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for pads." );
  431. // minimal segment count to approximate a circle to create the polygonal pad shape
  432. // This minimal value is mainly for very small pads, like SM0402.
  433. // Most of time pads are using the segment count given by aError value.
  434. const int pad_min_seg_per_circle_count = 16;
  435. double angle = m_orient;
  436. int dx = m_size.x / 2;
  437. int dy = m_size.y / 2;
  438. wxPoint padShapePos = ShapePos(); // Note: for pad having a shape offset,
  439. // the pad position is NOT the shape position
  440. switch( GetShape() )
  441. {
  442. case PAD_SHAPE_CIRCLE:
  443. case PAD_SHAPE_OVAL:
  444. if( dx == dy )
  445. {
  446. TransformCircleToPolygon( aCornerBuffer, padShapePos, dx + aClearanceValue, aError );
  447. }
  448. else
  449. {
  450. int half_width = std::min( dx, dy );
  451. wxPoint delta( dx - half_width, dy - half_width );
  452. RotatePoint( &delta, angle );
  453. TransformOvalToPolygon( aCornerBuffer, padShapePos - delta, padShapePos + delta,
  454. ( half_width + aClearanceValue ) * 2, aError );
  455. }
  456. break;
  457. case PAD_SHAPE_TRAPEZOID:
  458. case PAD_SHAPE_RECT:
  459. {
  460. int ddx = GetShape() == PAD_SHAPE_TRAPEZOID ? m_deltaSize.x / 2 : 0;
  461. int ddy = GetShape() == PAD_SHAPE_TRAPEZOID ? m_deltaSize.y / 2 : 0;
  462. wxPoint corners[4];
  463. corners[0] = wxPoint( -dx - ddy, dy + ddx );
  464. corners[1] = wxPoint( dx + ddy, dy - ddx );
  465. corners[2] = wxPoint( dx - ddy, -dy + ddx );
  466. corners[3] = wxPoint( -dx + ddy, -dy - ddx );
  467. SHAPE_POLY_SET outline;
  468. outline.NewOutline();
  469. for( wxPoint& corner : corners )
  470. {
  471. RotatePoint( &corner, angle );
  472. corner += padShapePos;
  473. outline.Append( corner.x, corner.y );
  474. }
  475. if( aClearanceValue )
  476. {
  477. int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ),
  478. pad_min_seg_per_circle_count );
  479. double correction = GetCircletoPolyCorrectionFactor( numSegs );
  480. int clearance = KiROUND( aClearanceValue * correction );
  481. outline.Inflate( clearance, numSegs );
  482. // TODO: clamp the inflated polygon, because it is slightly too big:
  483. // it was inflated by a value slightly too big to keep rounded corners
  484. // ouside the pad area.
  485. }
  486. aCornerBuffer.Append( outline );
  487. }
  488. break;
  489. case PAD_SHAPE_CHAMFERED_RECT:
  490. case PAD_SHAPE_ROUNDRECT:
  491. {
  492. int radius = GetRoundRectCornerRadius() + aClearanceValue;
  493. int numSegs = std::max( GetArcToSegmentCount( radius, aError, 360.0 ),
  494. pad_min_seg_per_circle_count );
  495. double correction = GetCircletoPolyCorrectionFactor( numSegs );
  496. int clearance = KiROUND( aClearanceValue * correction );
  497. wxSize shapesize( m_size );
  498. radius = KiROUND( radius * correction );
  499. shapesize.x += clearance * 2;
  500. shapesize.y += clearance * 2;
  501. bool doChamfer = GetShape() == PAD_SHAPE_CHAMFERED_RECT;
  502. SHAPE_POLY_SET outline;
  503. TransformRoundChamferedRectToPolygon( outline, padShapePos, shapesize, angle, radius,
  504. doChamfer ? GetChamferRectRatio() : 0.0,
  505. doChamfer ? GetChamferPositions() : 0, aError );
  506. aCornerBuffer.Append( outline );
  507. }
  508. break;
  509. case PAD_SHAPE_CUSTOM:
  510. {
  511. SHAPE_POLY_SET outline;
  512. MergePrimitivesAsPolygon( &outline, aLayer );
  513. outline.Rotate( -DECIDEG2RAD( m_orient ) );
  514. outline.Move( VECTOR2I( m_pos ) );
  515. // TODO: do we need the Simplify() & Fracture() if we're not inflating?
  516. outline.Simplify( SHAPE_POLY_SET::PM_FAST );
  517. if( aClearanceValue )
  518. {
  519. int numSegs = std::max( GetArcToSegmentCount( aClearanceValue, aError, 360.0 ),
  520. pad_min_seg_per_circle_count );
  521. double correction = GetCircletoPolyCorrectionFactor( numSegs );
  522. int clearance = KiROUND( aClearanceValue * correction );
  523. outline.Inflate( clearance, numSegs );
  524. }
  525. outline.Fracture( SHAPE_POLY_SET::PM_FAST );
  526. aCornerBuffer.Append( outline );
  527. }
  528. break;
  529. default:
  530. wxFAIL_MSG( "D_PAD::TransformShapeWithClearanceToPolygon no implementation for "
  531. + PAD_SHAPE_T_asString( GetShape() ) );
  532. break;
  533. }
  534. }
  535. bool D_PAD::TransformHoleWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer, int aInflateValue,
  536. int aError ) const
  537. {
  538. wxSize drillsize = GetDrillSize();
  539. if( !drillsize.x || !drillsize.y )
  540. return false;
  541. const SHAPE_SEGMENT* seg = GetEffectiveHoleShape();
  542. TransformSegmentToPolygon( aCornerBuffer, (wxPoint) seg->GetSeg().A, (wxPoint) seg->GetSeg().B,
  543. aError, seg->GetWidth() + aInflateValue * 2 );
  544. return true;
  545. }
  546. void ZONE_CONTAINER::TransformShapeWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuffer,
  547. PCB_LAYER_ID aLayer, int aClearance,
  548. int aError, bool ignoreLineWidth ) const
  549. {
  550. wxASSERT_MSG( !ignoreLineWidth, "IgnoreLineWidth has no meaning for zones." );
  551. if( !m_FilledPolysList.count( aLayer ) )
  552. return;
  553. aCornerBuffer = m_FilledPolysList.at( aLayer );
  554. aCornerBuffer.Inflate( aClearance, aError );
  555. aCornerBuffer.Simplify( SHAPE_POLY_SET::PM_STRICTLY_SIMPLE );
  556. }