KiCad PCB EDA Suite
microwave_inductor.cpp File Reference
#include <base_units.h>
#include <board_commit.h>
#include <board_design_settings.h>
#include <pad.h>
#include <fp_shape.h>
#include <footprint.h>
#include <confirm.h>
#include <dialogs/dialog_text_entry.h>
#include <geometry/geometry_utils.h>
#include <math/util.h>
#include <microwave/microwave_tool.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h>
#include <pcb_edit_frame.h>
#include <validators.h>

Go to the source code of this file.

Macros

#define ADJUST_SIZE   0.988
 

Enumerations

enum  INDUCTOR_S_SHAPE_RESULT { INDUCTOR_S_SHAPE_RESULT::OK, INDUCTOR_S_SHAPE_RESULT::TOO_LONG, INDUCTOR_S_SHAPE_RESULT::TOO_SHORT, INDUCTOR_S_SHAPE_RESULT::NO_REPR }
 

Functions

static void gen_arc (std::vector< wxPoint > &aBuffer, const wxPoint &aStartPoint, const wxPoint &aCenter, int a_ArcAngle)
 Function gen_arc generates an arc using arc approximation by lines: Center aCenter Angle "angle" (in 0.1 deg) More...
 
static INDUCTOR_S_SHAPE_RESULT BuildCornersList_S_Shape (std::vector< wxPoint > &aBuffer, const wxPoint &aStartPoint, const wxPoint &aEndPoint, int aLength, int aWidth)
 Function BuildCornersList_S_Shape Create a path like a S-shaped coil. More...
 

Macro Definition Documentation

◆ ADJUST_SIZE

#define ADJUST_SIZE   0.988

Enumeration Type Documentation

◆ INDUCTOR_S_SHAPE_RESULT

Enumerator
OK 
TOO_LONG 

S-shape constructed.

TOO_SHORT 

Requested length too long.

NO_REPR 

Requested length too short.

Definition at line 79 of file microwave_inductor.cpp.

80 {
81  OK,
82  TOO_LONG,
83  TOO_SHORT,
84  NO_REPR,
85 };
#define OK
Requested length too short.
Requested length too long.

Function Documentation

◆ BuildCornersList_S_Shape()

static INDUCTOR_S_SHAPE_RESULT BuildCornersList_S_Shape ( std::vector< wxPoint > &  aBuffer,
const wxPoint &  aStartPoint,
const wxPoint &  aEndPoint,
int  aLength,
int  aWidth 
)
static

Function BuildCornersList_S_Shape Create a path like a S-shaped coil.

Parameters
aBuffer= a buffer where to store points (ends of segments)
aStartPoint= starting point of the path
aEndPoint= ending point of the path
aLength= full length of the path
aWidth= segment width

Definition at line 97 of file microwave_inductor.cpp.

99 {
100 /* We must determine:
101  * segm_count = number of segments perpendicular to the direction
102  * segm_len = length of a strand
103  * radius = radius of rounded parts of the coil
104  * stubs_len = length of the 2 stubs( segments parallel to the direction)
105  * connecting the start point to the start point of the S shape
106  * and the ending point to the end point of the S shape
107  * The equations are (assuming the area size of the entire shape is Size:
108  * Size.x = 2 * radius + segm_len
109  * Size.y = (segm_count + 2 ) * 2 * radius + 2 * stubs_len
110  * aInductorPattern.m_length = 2 * delta // connections to the coil
111  * + (segm_count-2) * segm_len // length of the strands except 1st and last
112  * + (segm_count) * (PI * radius) // length of rounded
113  * segm_len + / 2 - radius * 2) // length of 1st and last bit
114  *
115  * The constraints are:
116  * segm_count >= 2
117  * radius < m_Size.x
118  * Size.y = (radius * 4) + (2 * stubs_len)
119  * segm_len > radius * 2
120  *
121  * The calculation is conducted in the following way:
122  * first:
123  * segm_count = 2
124  * radius = 4 * Size.x (arbitrarily fixed value)
125  * Then:
126  * Increasing the number of segments to the desired length
127  * (radius decreases if necessary)
128  */
129  wxPoint size;
130 
131  // This scale factor adjusts the arc length to handle
132  // the arc to segment approximation.
133  // because we use SEGM_COUNT_PER_360DEG segment to approximate a circle,
134  // the trace len must be corrected when calculated using arcs
135  // this factor adjust calculations and must be changed if SEGM_COUNT_PER_360DEG is modified
136  // because trace using segment is shorter the corresponding arc
137  // ADJUST_SIZE is the ratio between tline len and the arc len for an arc
138  // of 360/ADJUST_SIZE angle
139  #define ADJUST_SIZE 0.988
140 
141  auto pt = aEndPoint - aStartPoint;
142  double angle = -ArcTangente( pt.y, pt.x );
143  int min_len = KiROUND( EuclideanNorm( pt ) );
144  int segm_len = 0; // length of segments
145  int full_len; // full len of shape (sum of length of all segments + arcs)
146 
147 
148  /* Note: calculations are made for a vertical coil (more easy calculations)
149  * and after points are rotated to their actual position
150  * So the main direction is the Y axis.
151  * the 2 stubs are on the Y axis
152  * the others segments are parallel to the X axis.
153  */
154 
155  // Calculate the size of area (for a vertical shape)
156  size.x = min_len / 2;
157  size.y = min_len;
158 
159  // Choose a reasonable starting value for the radius of the arcs.
160  int radius = std::min( aWidth * 5, size.x / 4 );
161 
162  int segm_count; // number of full len segments
163  // the half size segments (first and last segment) are not counted here
164  int stubs_len = 0; // length of first or last segment (half size of others segments)
165 
166  for( segm_count = 0; ; segm_count++ )
167  {
168  stubs_len = ( size.y - ( radius * 2 * (segm_count + 2 ) ) ) / 2;
169 
170  if( stubs_len < size.y / 10 ) // Reduce radius.
171  {
172  stubs_len = size.y / 10;
173  radius = ( size.y - (2 * stubs_len) ) / ( 2 * (segm_count + 2) );
174 
175  if( radius < aWidth ) // Radius too small.
176  {
177  // Unable to create line: Requested length value is too large for room
179  }
180  }
181 
182  segm_len = size.x - ( radius * 2 );
183  full_len = 2 * stubs_len; // Length of coil connections.
184  full_len += segm_len * segm_count; // Length of full length segments.
185  full_len += KiROUND( ( segm_count + 2 ) * M_PI * ADJUST_SIZE * radius ); // Ard arcs len
186  full_len += segm_len - (2 * radius); // Length of first and last segments
187  // (half size segments len = segm_len/2 - radius).
188 
189  if( full_len >= aLength )
190  break;
191  }
192 
193  // Adjust len by adjusting segm_len:
194  int delta_size = full_len - aLength;
195 
196  // reduce len of the segm_count segments + 2 half size segments (= 1 full size segment)
197  segm_len -= delta_size / (segm_count + 1);
198 
199  // at this point, it could still be that the requested length is too
200  // short (because 4 quarter-circles are too long)
201  // to fix this is a relatively complex numerical problem which probably
202  // needs a refactor in this area. For now, just reject these cases:
203  {
204  const int min_total_length = 2 * stubs_len + 2 * M_PI * ADJUST_SIZE * radius;
205  if( min_total_length > aLength )
206  {
207  // we can't express this inductor with 90-deg arcs of this radius
209  }
210  }
211 
212  if( segm_len - 2 * radius < 0 )
213  {
214  // we can't represent this exact requested length with this number
215  // of segments (using the current algorithm). This stems from when
216  // you add a segment, you also add another half-circle, so there's a
217  // little bit of "dead" space.
218  // It's a bit ugly to just reject the input, as it might be possible
219  // to tweak the radius, but, again, that probably needs a refactor.
221  }
222 
223  // Generate first line (the first stub) and first arc (90 deg arc)
224  pt = aStartPoint;
225  aBuffer.push_back( pt );
226  pt.y += stubs_len;
227  aBuffer.push_back( pt );
228 
229  auto centre = pt;
230  centre.x -= radius;
231  gen_arc( aBuffer, pt, centre, -900 );
232  pt = aBuffer.back();
233 
234  int half_size_seg_len = segm_len / 2 - radius;
235 
236  if( half_size_seg_len )
237  {
238  pt.x -= half_size_seg_len;
239  aBuffer.push_back( pt );
240  }
241 
242  // Create shape.
243  int ii;
244  int sign = 1;
245  segm_count += 1; // increase segm_count to create the last half_size segment
246 
247  for( ii = 0; ii < segm_count; ii++ )
248  {
249  int arc_angle;
250 
251  if( ii & 1 ) // odd order arcs are greater than 0
252  sign = -1;
253  else
254  sign = 1;
255 
256  arc_angle = 1800 * sign;
257  centre = pt;
258  centre.y += radius;
259  gen_arc( aBuffer, pt, centre, arc_angle );
260  pt = aBuffer.back();
261  pt.x += segm_len * sign;
262  aBuffer.push_back( pt );
263  }
264 
265  // The last point is false:
266  // it is the end of a full size segment, but must be
267  // the end of the second half_size segment. Change it.
268  sign *= -1;
269  aBuffer.back().x = aStartPoint.x + radius * sign;
270 
271  // create last arc
272  pt = aBuffer.back();
273  centre = pt;
274  centre.y += radius;
275  gen_arc( aBuffer, pt, centre, 900 * sign );
276 
277  // Rotate point
278  angle += 900;
279 
280  for( unsigned jj = 0; jj < aBuffer.size(); jj++ )
281  {
282  RotatePoint( &aBuffer[jj], aStartPoint, angle );
283  }
284 
285  // push last point (end point)
286  aBuffer.push_back( aEndPoint );
287 
289 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
int sign(T val)
Definition: util.h:104
void RotatePoint(int *pX, int *pY, double angle)
Definition: trigo.cpp:229
static void gen_arc(std::vector< wxPoint > &aBuffer, const wxPoint &aStartPoint, const wxPoint &aCenter, int a_ArcAngle)
Function gen_arc generates an arc using arc approximation by lines: Center aCenter Angle "angle" (in ...
#define ADJUST_SIZE
static DIRECTION_45::AngleType angle(const VECTOR2I &a, const VECTOR2I &b)
Requested length too short.
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
double ArcTangente(int dy, int dx)
Definition: trigo.cpp:183
Requested length too long.

References ADJUST_SIZE, PNS::angle(), ArcTangente(), EuclideanNorm(), gen_arc(), KiROUND(), NO_REPR, OK, RotatePoint(), sign(), TOO_LONG, and TOO_SHORT.

Referenced by MICROWAVE_TOOL::createMicrowaveInductor().

◆ gen_arc()

static void gen_arc ( std::vector< wxPoint > &  aBuffer,
const wxPoint &  aStartPoint,
const wxPoint &  aCenter,
int  a_ArcAngle 
)
static

Function gen_arc generates an arc using arc approximation by lines: Center aCenter Angle "angle" (in 0.1 deg)

Parameters
aBuffer= a buffer to store points.
aStartPoint= starting point of arc.
aCenter= arc centre.
a_ArcAngle= arc length in 0.1 degrees.

Definition at line 50 of file microwave_inductor.cpp.

54 {
55  auto first_point = aStartPoint - aCenter;
56  auto radius = KiROUND( EuclideanNorm( first_point ) );
57  int seg_count = GetArcToSegmentCount( radius, ARC_HIGH_DEF, a_ArcAngle / 10.0 );
58 
59  double increment_angle = (double) a_ArcAngle * M_PI / 1800 / seg_count;
60 
61  // Creates nb_seg point to approximate arc by segments:
62  for( int ii = 1; ii <= seg_count; ii++ )
63  {
64  double rot_angle = increment_angle * ii;
65  double fcos = cos( rot_angle );
66  double fsin = sin( rot_angle );
67  wxPoint currpt;
68 
69  // Rotate current point:
70  currpt.x = KiROUND( ( first_point.x * fcos + first_point.y * fsin ) );
71  currpt.y = KiROUND( ( first_point.y * fcos - first_point.x * fsin ) );
72 
73  auto corner = aCenter + currpt;
74  aBuffer.push_back( corner );
75  }
76 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:146
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:73
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)

References EuclideanNorm(), GetArcToSegmentCount(), and KiROUND().

Referenced by BuildCornersList_S_Shape().