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.

261 lines
9.1 KiB

  1. /**
  2. * @file convert_basic_shapes_to_polygon.cpp
  3. */
  4. /*
  5. * This program source code file is part of KiCad, a free EDA CAD application.
  6. *
  7. * Copyright (C) 2012 Jean-Pierre Charras, jp.charras at wanadoo.fr
  8. * Copyright (C) 1992-2012 KiCad Developers, see change_log.txt for contributors.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you may find one here:
  22. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  23. * or you may search the http://www.gnu.org website for the version 2 license,
  24. * or you may write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  26. */
  27. #include <vector>
  28. #include <fctsys.h>
  29. #include <trigo.h>
  30. #include <macros.h>
  31. #include <common.h>
  32. #include <convert_basic_shapes_to_polygon.h>
  33. /**
  34. * Function TransformCircleToPolygon
  35. * convert a circle to a polygon, using multiple straight lines
  36. * @param aCornerBuffer = a buffer to store the polygon
  37. * @param aCenter = the center of the circle
  38. * @param aRadius = the radius of the circle
  39. * @param aCircleToSegmentsCount = the number of segments to approximate a circle
  40. * Note: the polygon is inside the circle, so if you want to have the polygon
  41. * outside the circle, you should give aRadius calculated with a corrrection factor
  42. */
  43. void TransformCircleToPolygon( CPOLYGONS_LIST& aCornerBuffer,
  44. wxPoint aCenter, int aRadius,
  45. int aCircleToSegmentsCount )
  46. {
  47. wxPoint corner_position;
  48. int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
  49. int halfstep = 1800 / aCircleToSegmentsCount; // the starting value for rot angles
  50. for( int ii = 0; ii < aCircleToSegmentsCount; ii++ )
  51. {
  52. corner_position.x = aRadius;
  53. corner_position.y = 0;
  54. int angle = (ii * delta) + halfstep;
  55. RotatePoint( &corner_position.x, &corner_position.y, angle );
  56. corner_position += aCenter;
  57. CPolyPt polypoint( corner_position.x, corner_position.y );
  58. aCornerBuffer.Append( polypoint );
  59. }
  60. aCornerBuffer.CloseLastContour();
  61. }
  62. /**
  63. * Function TransformRoundedEndsSegmentToPolygon
  64. * convert a segment with rounded ends to a polygon
  65. * Convert arcs to multiple straight lines
  66. * @param aCornerBuffer = a buffer to store the polygon
  67. * @param aStart = the segment start point coordinate
  68. * @param aEnd = the segment end point coordinate
  69. * @param aCircleToSegmentsCount = the number of segments to approximate a circle
  70. * @param aWidth = the segment width
  71. * Note: the polygon is inside the arc ends, so if you want to have the polygon
  72. * outside the circle, you should give aStart and aEnd calculated with a correction factor
  73. */
  74. void TransformRoundedEndsSegmentToPolygon( CPOLYGONS_LIST& aCornerBuffer,
  75. wxPoint aStart, wxPoint aEnd,
  76. int aCircleToSegmentsCount,
  77. int aWidth )
  78. {
  79. int radius = aWidth / 2;
  80. wxPoint endp = aEnd - aStart; // end point coordinate for the same segment starting at (0,0)
  81. wxPoint startp = aStart;
  82. wxPoint corner;
  83. CPolyPt polypoint;
  84. // normalize the position in order to have endp.x >= 0;
  85. if( endp.x < 0 )
  86. {
  87. endp = aStart - aEnd;
  88. startp = aEnd;
  89. }
  90. double delta_angle = ArcTangente( endp.y, endp.x ); // delta_angle is in 0.1 degrees
  91. int seg_len = KiROUND( EuclideanNorm( endp ) );
  92. int delta = 3600 / aCircleToSegmentsCount; // rot angle in 0.1 degree
  93. // Compute the outlines of the segment, and creates a polygon
  94. // add right rounded end:
  95. for( int ii = 0; ii < 1800; ii += delta )
  96. {
  97. corner = wxPoint( 0, radius );
  98. RotatePoint( &corner, ii );
  99. corner.x += seg_len;
  100. RotatePoint( &corner, -delta_angle );
  101. corner += startp;
  102. polypoint.x = corner.x;
  103. polypoint.y = corner.y;
  104. aCornerBuffer.Append( polypoint );
  105. }
  106. // Finish arc:
  107. corner = wxPoint( seg_len, -radius );
  108. RotatePoint( &corner, -delta_angle );
  109. corner += startp;
  110. polypoint.x = corner.x;
  111. polypoint.y = corner.y;
  112. aCornerBuffer.Append( polypoint );
  113. // add left rounded end:
  114. for( int ii = 0; ii < 1800; ii += delta )
  115. {
  116. corner = wxPoint( 0, -radius );
  117. RotatePoint( &corner, ii );
  118. RotatePoint( &corner, -delta_angle );
  119. corner += startp;
  120. polypoint.x = corner.x;
  121. polypoint.y = corner.y;
  122. aCornerBuffer.Append( polypoint );
  123. }
  124. // Finish arc:
  125. corner = wxPoint( 0, radius );
  126. RotatePoint( &corner, -delta_angle );
  127. corner += startp;
  128. polypoint.x = corner.x;
  129. polypoint.y = corner.y;
  130. aCornerBuffer.Append( polypoint );
  131. aCornerBuffer.CloseLastContour();
  132. }
  133. /**
  134. * Function TransformArcToPolygon
  135. * Creates a polygon from an Arc
  136. * Convert arcs to multiple straight segments
  137. * @param aCornerBuffer = a buffer to store the polygon
  138. * @param aCentre = centre of the arc or circle
  139. * @param aStart = start point of the arc, or a point on the circle
  140. * @param aArcAngle = arc angle in 0.1 degrees. For a circle, aArcAngle = 3600
  141. * @param aCircleToSegmentsCount = the number of segments to approximate a circle
  142. * @param aWidth = width (thickness) of the line
  143. */
  144. void TransformArcToPolygon( CPOLYGONS_LIST& aCornerBuffer,
  145. wxPoint aCentre, wxPoint aStart, double aArcAngle,
  146. int aCircleToSegmentsCount, int aWidth )
  147. {
  148. wxPoint arc_start, arc_end;
  149. int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
  150. arc_end = arc_start = aStart;
  151. if( aArcAngle != 3600 )
  152. {
  153. RotatePoint( &arc_end, aCentre, -aArcAngle );
  154. }
  155. if( aArcAngle < 0 )
  156. {
  157. EXCHG( arc_start, arc_end );
  158. NEGATE( aArcAngle );
  159. }
  160. // Compute the ends of segments and creates poly
  161. wxPoint curr_end = arc_start;
  162. wxPoint curr_start = arc_start;
  163. for( int ii = delta; ii < aArcAngle; ii += delta )
  164. {
  165. curr_end = arc_start;
  166. RotatePoint( &curr_end, aCentre, -ii );
  167. TransformRoundedEndsSegmentToPolygon( aCornerBuffer, curr_start, curr_end,
  168. aCircleToSegmentsCount, aWidth );
  169. curr_start = curr_end;
  170. }
  171. if( curr_end != arc_end )
  172. TransformRoundedEndsSegmentToPolygon( aCornerBuffer,
  173. curr_end, arc_end,
  174. aCircleToSegmentsCount, aWidth );
  175. }
  176. /**
  177. * Function TransformRingToPolygon
  178. * Creates a polygon from a ring
  179. * Convert arcs to multiple straight segments
  180. * @param aCornerBuffer = a buffer to store the polygon
  181. * @param aCentre = centre of the arc or circle
  182. * @param aRadius = radius of the circle
  183. * @param aCircleToSegmentsCount = the number of segments to approximate a circle
  184. * @param aWidth = width (thickness) of the ring
  185. */
  186. void TransformRingToPolygon( CPOLYGONS_LIST& aCornerBuffer,
  187. wxPoint aCentre, int aRadius,
  188. int aCircleToSegmentsCount, int aWidth )
  189. {
  190. int delta = 3600 / aCircleToSegmentsCount; // rotate angle in 0.1 degree
  191. // Compute the corners posituions and creates poly
  192. wxPoint curr_point;
  193. int inner_radius = aRadius - ( aWidth / 2 );
  194. int outer_radius = inner_radius + aWidth;
  195. CPolyPt polycorner;
  196. // Draw the inner circle of the ring
  197. for( int ii = 0; ii < 3600; ii += delta )
  198. {
  199. curr_point.x = inner_radius;
  200. curr_point.y = 0;
  201. RotatePoint( &curr_point, ii );
  202. curr_point += aCentre;
  203. polycorner.x = curr_point.x;
  204. polycorner.y = curr_point.y;
  205. aCornerBuffer.Append( polycorner );
  206. }
  207. // Draw the last point of inner circle
  208. polycorner.x = aCentre.x + inner_radius;
  209. polycorner.y = aCentre.y;
  210. aCornerBuffer.Append( polycorner );
  211. // Draw the outer circle of the ring
  212. for( int ii = 0; ii < 3600; ii += delta )
  213. {
  214. curr_point.x = outer_radius;
  215. curr_point.y = 0;
  216. RotatePoint( &curr_point, -ii );
  217. curr_point += aCentre;
  218. polycorner.x = curr_point.x;
  219. polycorner.y = curr_point.y;
  220. aCornerBuffer.Append( polycorner );
  221. }
  222. // Draw the last point of outer circle
  223. polycorner.x = aCentre.x + outer_radius;
  224. polycorner.y = aCentre.y;
  225. aCornerBuffer.Append( polycorner );
  226. // Close the polygon
  227. polycorner.x = aCentre.x + inner_radius;
  228. polycorner.end_contour = true;
  229. aCornerBuffer.Append( polycorner );
  230. }