KiCad PCB EDA Suite
microwave_inductor.cpp File Reference
#include <wx/wx.h>
#include <base_units.h>
#include <board_commit.h>
#include <class_pad.h>
#include <class_edge_mod.h>
#include <class_module.h>
#include <confirm.h>
#include <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 80 of file microwave_inductor.cpp.

81 {
82  OK,
83  TOO_LONG,
84  TOO_SHORT,
85  NO_REPR,
86 };
#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 98 of file microwave_inductor.cpp.

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

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

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

Referenced by BuildCornersList_S_Shape().