KiCad PCB EDA Suite
microwave_inductor.cpp File Reference
#include "microwave_inductor.h"
#include <wx/wx.h>
#include <base_units.h>
#include <dialog_text_entry.h>
#include <geometry/geometry_utils.h>
#include <pcb_edit_frame.h>
#include <validators.h>
#include <class_pad.h>
#include <class_edge_mod.h>
#include <class_module.h>
#include <math/util.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 81 of file microwave_inductor.cpp.

82 {
83  OK,
84  TOO_LONG,
85  TOO_SHORT,
86  NO_REPR,
87 };
Definition: erc.h:42
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 99 of file microwave_inductor.cpp.

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

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

Referenced by MWAVE::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 52 of file microwave_inductor.cpp.

56 {
57  auto first_point = aStartPoint - aCenter;
58  auto radius = KiROUND( EuclideanNorm( first_point ) );
59  int seg_count = std::max( GetArcToSegmentCount( radius, ARC_HIGH_DEF, a_ArcAngle / 10.0 ), 3 );
60 
61  double increment_angle = (double) a_ArcAngle * M_PI / 1800 / seg_count;
62 
63  // Creates nb_seg point to approximate arc by segments:
64  for( int ii = 1; ii <= seg_count; ii++ )
65  {
66  double rot_angle = increment_angle * ii;
67  double fcos = cos( rot_angle );
68  double fsin = sin( rot_angle );
69  wxPoint currpt;
70 
71  // Rotate current point:
72  currpt.x = KiROUND( ( first_point.x * fcos + first_point.y * fsin ) );
73  currpt.y = KiROUND( ( first_point.y * fcos - first_point.x * fsin ) );
74 
75  auto corner = aCenter + currpt;
76  aBuffer.push_back( corner );
77  }
78 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:128
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:61
int GetArcToSegmentCount(int aRadius, int aErrorMax, double aArcAngleDegree)

References EuclideanNorm(), GetArcToSegmentCount(), KiROUND(), wxPoint::x, and wxPoint::y.

Referenced by BuildCornersList_S_Shape().