diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 8065741813..4cd63eb4a5 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -194,6 +194,10 @@ set( PCBNEW_AUTOROUTER_SRCS autorouter/work.cpp ) +set( PCBNEW_MICROWAVE_SRCS + microwave/microwave_inductor.cpp + ) + set( PCBNEW_CLASS_SRCS board_commit.cpp tool_modview.cpp @@ -315,8 +319,12 @@ set( PCBNEW_CLASS_SRCS footprint_preview_panel.cpp ) -set( PCBNEW_SRCS ${PCBNEW_AUTOROUTER_SRCS} ${PCBNEW_CLASS_SRCS} ${PCBNEW_DIALOGS} ) - +set( PCBNEW_SRCS + ${PCBNEW_AUTOROUTER_SRCS} + ${PCBNEW_MICROWAVE_SRCS} + ${PCBNEW_CLASS_SRCS} + ${PCBNEW_DIALOGS} + ) # extra sources from common set( PCBNEW_COMMON_SRCS diff --git a/pcbnew/microwave/microwave_inductor.cpp b/pcbnew/microwave/microwave_inductor.cpp new file mode 100644 index 0000000000..f7a875a798 --- /dev/null +++ b/pcbnew/microwave/microwave_inductor.cpp @@ -0,0 +1,405 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "microwave_inductor.h" + +#include + +#include +#include +#include + +#include +#include +#include + + +using namespace MWAVE; + +/** + * Function gen_arc + * generates an arc using arc approximation by lines: + * Center aCenter + * Angle "angle" (in 0.1 deg) + * @param aBuffer = a buffer to store points. + * @param aStartPoint = starting point of arc. + * @param aCenter = arc centre. + * @param a_ArcAngle = arc length in 0.1 degrees. + */ +static void gen_arc( std::vector & aBuffer, + const wxPoint& aStartPoint, + const wxPoint& aCenter, + int a_ArcAngle ) +{ + const int SEGM_COUNT_PER_360DEG = 16; + auto first_point = aStartPoint - aCenter; + int seg_count = ( ( abs( a_ArcAngle ) ) * SEGM_COUNT_PER_360DEG ) / 3600; + + if( seg_count == 0 ) + seg_count = 1; + + double increment_angle = (double) a_ArcAngle * M_PI / 1800 / seg_count; + + // Creates nb_seg point to approximate arc by segments: + for( int ii = 1; ii <= seg_count; ii++ ) + { + double rot_angle = increment_angle * ii; + double fcos = cos( rot_angle ); + double fsin = sin( rot_angle ); + wxPoint currpt; + + // Rotate current point: + currpt.x = KiROUND( ( first_point.x * fcos + first_point.y * fsin ) ); + currpt.y = KiROUND( ( first_point.y * fcos - first_point.x * fsin ) ); + + auto corner = aCenter + currpt; + aBuffer.push_back( corner ); + } +} + + +/** + * Function BuildCornersList_S_Shape + * Create a path like a S-shaped coil + * @param aBuffer = a buffer where to store points (ends of segments) + * @param aStartPoint = starting point of the path + * @param aEndPoint = ending point of the path + * @param aLength = full length of the path + * @param aWidth = segment width + */ +static int BuildCornersList_S_Shape( std::vector & aBuffer, + const wxPoint& aStartPoint, + const wxPoint& aEndPoint, + int aLength, int aWidth ) +{ +/* We must determine: + * segm_count = number of segments perpendicular to the direction + * segm_len = length of a strand + * radius = radius of rounded parts of the coil + * stubs_len = length of the 2 stubs( segments parallel to the direction) + * connecting the start point to the start point of the S shape + * and the ending point to the end point of the S shape + * The equations are (assuming the area size of the entire shape is Size: + * Size.x = 2 * radius + segm_len + * Size.y = (segm_count + 2 ) * 2 * radius + 2 * stubs_len + * inductorPattern.m_length = 2 * delta // connections to the coil + * + (segm_count-2) * segm_len // length of the strands except 1st and last + * + (segm_count) * (PI * radius) // length of rounded + * segm_len + / 2 - radius * 2) // length of 1st and last bit + * + * The constraints are: + * segm_count >= 2 + * radius < m_Size.x + * Size.y = (radius * 4) + (2 * stubs_len) + * segm_len > radius * 2 + * + * The calculation is conducted in the following way: + * first: + * segm_count = 2 + * radius = 4 * Size.x (arbitrarily fixed value) + * Then: + * Increasing the number of segments to the desired length + * (radius decreases if necessary) + */ + wxPoint size; + + // This scale factor adjusts the arc length to handle + // the arc to segment approximation. + // because we use SEGM_COUNT_PER_360DEG segment to approximate a circle, + // the trace len must be corrected when calculated using arcs + // this factor adjust calculations and must be changed if SEGM_COUNT_PER_360DEG is modified + // because trace using segment is shorter the corresponding arc + // ADJUST_SIZE is the ratio between tline len and the arc len for an arc + // of 360/ADJUST_SIZE angle + #define ADJUST_SIZE 0.988 + + auto pt = aEndPoint - aStartPoint; + double angle = -ArcTangente( pt.y, pt.x ); + int min_len = KiROUND( EuclideanNorm( pt ) ); + int segm_len = 0; // length of segments + int full_len; // full len of shape (sum of length of all segments + arcs) + + + /* Note: calculations are made for a vertical coil (more easy calculations) + * and after points are rotated to their actual position + * So the main direction is the Y axis. + * the 2 stubs are on the Y axis + * the others segments are parallel to the X axis. + */ + + // Calculate the size of area (for a vertical shape) + size.x = min_len / 2; + size.y = min_len; + + // Choose a reasonable starting value for the radius of the arcs. + int radius = std::min( aWidth * 5, size.x / 4 ); + + int segm_count; // number of full len segments + // the half size segments (first and last segment) are not counted here + int stubs_len = 0; // length of first or last segment (half size of others segments) + + for( segm_count = 0; ; segm_count++ ) + { + stubs_len = ( size.y - ( radius * 2 * (segm_count + 2 ) ) ) / 2; + + if( stubs_len < size.y / 10 ) // Reduce radius. + { + stubs_len = size.y / 10; + radius = ( size.y - (2 * stubs_len) ) / ( 2 * (segm_count + 2) ); + + if( radius < aWidth ) // Radius too small. + { + // Unable to create line: Requested length value is too large for room + return 0; + } + } + + segm_len = size.x - ( radius * 2 ); + full_len = 2 * stubs_len; // Length of coil connections. + full_len += segm_len * segm_count; // Length of full length segments. + full_len += KiROUND( ( segm_count + 2 ) * M_PI * ADJUST_SIZE * radius ); // Ard arcs len + full_len += segm_len - (2 * radius); // Length of first and last segments + // (half size segments len = segm_len/2 - radius). + + if( full_len >= aLength ) + break; + } + + // Adjust len by adjusting segm_len: + int delta_size = full_len - aLength; + + // reduce len of the segm_count segments + 2 half size segments (= 1 full size segment) + segm_len -= delta_size / (segm_count + 1); + + // Generate first line (the first stub) and first arc (90 deg arc) + pt = aStartPoint; + aBuffer.push_back( pt ); + pt.y += stubs_len; + aBuffer.push_back( pt ); + + auto centre = pt; + centre.x -= radius; + gen_arc( aBuffer, pt, centre, -900 ); + pt = aBuffer.back(); + + int half_size_seg_len = segm_len / 2 - radius; + + if( half_size_seg_len ) + { + pt.x -= half_size_seg_len; + aBuffer.push_back( pt ); + } + + // Create shape. + int ii; + int sign = 1; + segm_count += 1; // increase segm_count to create the last half_size segment + + for( ii = 0; ii < segm_count; ii++ ) + { + int arc_angle; + + if( ii & 1 ) // odd order arcs are greater than 0 + sign = -1; + else + sign = 1; + + arc_angle = 1800 * sign; + centre = pt; + centre.y += radius; + gen_arc( aBuffer, pt, centre, arc_angle ); + pt = aBuffer.back(); + pt.x += segm_len * sign; + aBuffer.push_back( pt ); + } + + // The last point is false: + // it is the end of a full size segment, but must be + // the end of the second half_size segment. Change it. + sign *= -1; + aBuffer.back().x = aStartPoint.x + radius * sign; + + // create last arc + pt = aBuffer.back(); + centre = pt; + centre.y += radius; + gen_arc( aBuffer, pt, centre, 900 * sign ); + aBuffer.back(); + + // Rotate point + angle += 900; + + for( unsigned jj = 0; jj < aBuffer.size(); jj++ ) + { + RotatePoint( &aBuffer[jj].x, &aBuffer[jj].y, aStartPoint.x, aStartPoint.y, angle ); + } + + // push last point (end point) + aBuffer.push_back( aEndPoint ); + + return 1; +} + + +MODULE* MWAVE::CreateMicrowaveInductor( INDUCTOR_PATTERN& inductorPattern, + PCB_EDIT_FRAME* aPcbFrame, wxString& aErrorMessage ) +{ + /* Build a microwave inductor footprint. + * - Length Mself.lng + * - Extremities Mself.m_Start and Mself.m_End + * We must determine: + * Mself.nbrin = number of segments perpendicular to the direction + * (The coil nbrin will demicercles + 1 + 2 1 / 4 circle) + * Mself.lbrin = length of a strand + * Mself.radius = radius of rounded parts of the coil + * Mself.delta = segments extremities connection between him and the coil even + * + * The equations are + * Mself.m_Size.x = 2 * Mself.radius + Mself.lbrin + * Mself.m_Size.y * Mself.delta = 2 + 2 * Mself.nbrin * Mself.radius + * Mself.lng = 2 * Mself.delta / / connections to the coil + + (Mself.nbrin-2) * Mself.lbrin / / length of the strands except 1st and last + + (Mself.nbrin 1) * (PI * Mself.radius) / / length of rounded + * Mself.lbrin + / 2 - Melf.radius * 2) / / length of 1st and last bit + * + * The constraints are: + * Nbrin >= 2 + * Mself.radius < Mself.m_Size.x + * Mself.m_Size.y = Mself.radius * 4 + 2 * Mself.raccord + * Mself.lbrin> Mself.radius * 2 + * + * The calculation is conducted in the following way: + * Initially: + * Nbrin = 2 + * Radius = 4 * m_Size.x (arbitrarily fixed value) + * Then: + * Increasing the number of segments to the desired length + * (Radius decreases if necessary) + */ + + D_PAD* pad; + int ll; + wxString msg; + + auto pt = inductorPattern.m_End - inductorPattern.m_Start; + int min_len = KiROUND( EuclideanNorm( pt ) ); + inductorPattern.m_length = min_len; + + // Enter the desired length. + msg = StringFromValue( g_UserUnit, inductorPattern.m_length ); + wxTextEntryDialog dlg( NULL, wxEmptyString, _( "Length of Trace:" ), msg ); + + if( dlg.ShowModal() != wxID_OK ) + return NULL; // canceled by user + + msg = dlg.GetValue(); + inductorPattern.m_length = ValueFromString( g_UserUnit, msg ); + + // Control values (ii = minimum length) + if( inductorPattern.m_length < min_len ) + { + aErrorMessage = _( "Requested length < minimum length" ); + return NULL; + } + + // Calculate the elements. + std::vector buffer; + ll = BuildCornersList_S_Shape( buffer, inductorPattern.m_Start, + inductorPattern.m_End, inductorPattern.m_length, + inductorPattern.m_Width ); + + if( !ll ) + { + aErrorMessage = _( "Requested length too large" ); + return NULL; + } + + // Generate footprint. the value is also used as footprint name. + msg.Empty(); + wxTextEntryDialog cmpdlg( NULL, wxEmptyString, _( "Component Value:" ), msg ); + cmpdlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &msg ) ); + + if( ( cmpdlg.ShowModal() != wxID_OK ) || msg.IsEmpty() ) + return NULL; // Aborted by user + + MODULE* module = aPcbFrame->CreateNewModule( msg ); + + // here the module is already in the BOARD, CreateNewModule() does that. + module->SetFPID( LIB_ID( std::string( "mw_inductor" ) ) ); + module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); + module->ClearFlags(); + module->SetPosition( inductorPattern.m_End ); + + // Generate segments + for( unsigned jj = 1; jj < buffer.size(); jj++ ) + { + EDGE_MODULE* PtSegm; + PtSegm = new EDGE_MODULE( module ); + PtSegm->SetStart( buffer[jj - 1] ); + PtSegm->SetEnd( buffer[jj] ); + PtSegm->SetWidth( inductorPattern.m_Width ); + PtSegm->SetLayer( module->GetLayer() ); + PtSegm->SetShape( S_SEGMENT ); + PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() ); + PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() ); + module->GraphicalItems().PushBack( PtSegm ); + } + + // Place a pad on each end of coil. + pad = new D_PAD( module ); + + module->Pads().PushFront( pad ); + + pad->SetPadName( "1" ); + pad->SetPosition( inductorPattern.m_End ); + pad->SetPos0( pad->GetPosition() - module->GetPosition() ); + + pad->SetSize( wxSize( inductorPattern.m_Width, inductorPattern.m_Width ) ); + + pad->SetLayerSet( LSET( module->GetLayer() ) ); + pad->SetAttribute( PAD_ATTRIB_SMD ); + pad->SetShape( PAD_SHAPE_CIRCLE ); + + D_PAD* newpad = new D_PAD( *pad ); + + module->Pads().Insert( newpad, pad->Next() ); + + pad = newpad; + pad->SetPadName( "2" ); + pad->SetPosition( inductorPattern.m_Start ); + pad->SetPos0( pad->GetPosition() - module->GetPosition() ); + + // Modify text positions. + wxPoint refPos( ( inductorPattern.m_Start.x + inductorPattern.m_End.x ) / 2, + ( inductorPattern.m_Start.y + inductorPattern.m_End.y ) / 2 ); + + wxPoint valPos = refPos; + + refPos.y -= module->Reference().GetTextSize().y; + module->Reference().SetPosition( refPos ); + valPos.y += module->Value().GetTextSize().y; + module->Value().SetPosition( valPos ); + + module->CalculateBoundingBox(); + return module; +} diff --git a/pcbnew/microwave/microwave_inductor.h b/pcbnew/microwave/microwave_inductor.h new file mode 100644 index 0000000000..1950192370 --- /dev/null +++ b/pcbnew/microwave/microwave_inductor.h @@ -0,0 +1,55 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef MICROWAVE_INDUCTOR__H_ +#define MICROWAVE_INDUCTOR__H_ + +#include // for wxPoint + +class MODULE; +class PCB_EDIT_FRAME; + +namespace MWAVE +{ + +/** + * Parameters for construction of a microwave inductor + */ +struct INDUCTOR_PATTERN +{ +public: + wxPoint m_Start; + wxPoint m_End; + int m_length; // full length trace. + int m_Width; // Trace width. +}; + +/** + * Creates an S-shaped coil footprint for microwave applications. + */ +MODULE* CreateMicrowaveInductor( INDUCTOR_PATTERN& aPattern, + PCB_EDIT_FRAME* aPcbFrame, wxString& aErrorMessage ); + +} + +#endif // MICROWAVE_INDUCTOR__H_ diff --git a/pcbnew/muonde.cpp b/pcbnew/muonde.cpp index ef86a00cac..d49014d93b 100644 --- a/pcbnew/muonde.cpp +++ b/pcbnew/muonde.cpp @@ -42,12 +42,14 @@ #include #include #include -#include +#include // #include #include #include +#include + #include static std::vector< wxRealPoint > PolyEdges; @@ -57,10 +59,6 @@ static int PolyShapeType; static void Exit_Self( EDA_DRAW_PANEL* aPanel, wxDC* aDC ); -static void gen_arc( std::vector & aBuffer, - wxPoint aStartPoint, - wxPoint aCenter, - int a_ArcAngle ); static void ShowBoundingBoxMicroWaveInductor( EDA_DRAW_PANEL* aPanel, wxDC* aDC, @@ -68,30 +66,11 @@ static void ShowBoundingBoxMicroWaveInductor( EDA_DRAW_PANEL* aPanel, bool aErase ); -static int BuildCornersList_S_Shape( std::vector & aBuffer, - wxPoint aStartPoint, wxPoint aEndPoint, - int aLength, int aWidth ); +///> An inductor pattern temporarily used during mu-wave inductor creation +static MWAVE::INDUCTOR_PATTERN s_inductor_pattern; -/** - * Creates a self-shaped coil for microwave applications. - */ -static MODULE* CreateMicrowaveInductor( PCB_EDIT_FRAME* aPcbFrame, wxString& aErrorMessage ); - - -class MUWAVE_INDUCTOR -{ -public: - wxPoint m_Start; - wxPoint m_End; - wxSize m_Size; - int m_length; // full length trace. - int m_Width; // Trace width. - // A flag set to true when mu-wave inductor is being created - bool m_Flag; -}; - -// An instance of MUWAVE_INDUCTOR temporary used during mu-wave inductor creation -static MUWAVE_INDUCTOR s_inductor_pattern; +///> A flag set to true when mu-wave inductor is being created +static bool s_inductorInProgress = false; /* This function shows on screen the bounding box of the inductor that will be @@ -152,14 +131,14 @@ void Exit_Self( EDA_DRAW_PANEL* aPanel, wxDC* aDC ) if( aPanel->IsMouseCaptured() ) aPanel->CallMouseCapture( aDC, wxDefaultPosition, false ); - s_inductor_pattern.m_Flag = false; + s_inductorInProgress = false; aPanel->SetMouseCapture( NULL, NULL ); } void PCB_EDIT_FRAME::Begin_Self( wxDC* DC ) { - if( s_inductor_pattern.m_Flag ) + if( s_inductorInProgress ) { m_canvas->CallMouseCapture( DC, wxDefaultPosition, false ); m_canvas->SetMouseCapture( NULL, NULL ); @@ -172,7 +151,10 @@ void PCB_EDIT_FRAME::Begin_Self( wxDC* DC ) s_inductor_pattern.m_Width = GetDesignSettings().GetCurrentTrackWidth(); s_inductor_pattern.m_End = GetCrossHairPosition(); - MODULE* footprint = CreateMicrowaveInductor( this, errorMessage ); + wxASSERT( s_inductorInProgress ); + s_inductorInProgress = false; + + MODULE* footprint = MWAVE::CreateMicrowaveInductor( s_inductor_pattern, this, errorMessage ); if( footprint ) { @@ -189,7 +171,7 @@ void PCB_EDIT_FRAME::Begin_Self( wxDC* DC ) s_inductor_pattern.m_Start = GetCrossHairPosition(); s_inductor_pattern.m_End = s_inductor_pattern.m_Start; - s_inductor_pattern.m_Flag = true; + s_inductorInProgress = true; // Update the initial coordinates. GetScreen()->m_O_Curseur = GetCrossHairPosition(); @@ -200,378 +182,6 @@ void PCB_EDIT_FRAME::Begin_Self( wxDC* DC ) } - -MODULE* CreateMicrowaveInductor( PCB_EDIT_FRAME* aPcbFrame, wxString& aErrorMessage ) -{ - /* Build a microwave inductor footprint. - * - Length Mself.lng - * - Extremities Mself.m_Start and Mself.m_End - * We must determine: - * Mself.nbrin = number of segments perpendicular to the direction - * (The coil nbrin will demicercles + 1 + 2 1 / 4 circle) - * Mself.lbrin = length of a strand - * Mself.radius = radius of rounded parts of the coil - * Mself.delta = segments extremities connection between him and the coil even - * - * The equations are - * Mself.m_Size.x = 2 * Mself.radius + Mself.lbrin - * Mself.m_Size.y * Mself.delta = 2 + 2 * Mself.nbrin * Mself.radius - * Mself.lng = 2 * Mself.delta / / connections to the coil - + (Mself.nbrin-2) * Mself.lbrin / / length of the strands except 1st and last - + (Mself.nbrin 1) * (PI * Mself.radius) / / length of rounded - * Mself.lbrin + / 2 - Melf.radius * 2) / / length of 1st and last bit - * - * The constraints are: - * Nbrin >= 2 - * Mself.radius < Mself.m_Size.x - * Mself.m_Size.y = Mself.radius * 4 + 2 * Mself.raccord - * Mself.lbrin> Mself.radius * 2 - * - * The calculation is conducted in the following way: - * Initially: - * Nbrin = 2 - * Radius = 4 * m_Size.x (arbitrarily fixed value) - * Then: - * Increasing the number of segments to the desired length - * (Radius decreases if necessary) - */ - - D_PAD* pad; - int ll; - wxString msg; - - wxASSERT( s_inductor_pattern.m_Flag ); - - s_inductor_pattern.m_Flag = false; - - wxPoint pt = s_inductor_pattern.m_End - s_inductor_pattern.m_Start; - int min_len = KiROUND( EuclideanNorm( pt ) ); - s_inductor_pattern.m_length = min_len; - - // Enter the desired length. - msg = StringFromValue( g_UserUnit, s_inductor_pattern.m_length ); - wxTextEntryDialog dlg( NULL, wxEmptyString, _( "Length of Trace:" ), msg ); - - if( dlg.ShowModal() != wxID_OK ) - return NULL; // canceled by user - - msg = dlg.GetValue(); - s_inductor_pattern.m_length = ValueFromString( g_UserUnit, msg ); - - // Control values (ii = minimum length) - if( s_inductor_pattern.m_length < min_len ) - { - aErrorMessage = _( "Requested length < minimum length" ); - return NULL; - } - - // Calculate the elements. - std::vector buffer; - ll = BuildCornersList_S_Shape( buffer, s_inductor_pattern.m_Start, - s_inductor_pattern.m_End, s_inductor_pattern.m_length, - s_inductor_pattern.m_Width ); - - if( !ll ) - { - aErrorMessage = _( "Requested length too large" ); - return NULL; - } - - // Generate footprint. the value is also used as footprint name. - msg.Empty(); - wxTextEntryDialog cmpdlg( NULL, wxEmptyString, _( "Component Value:" ), msg ); - cmpdlg.SetTextValidator( FILE_NAME_CHAR_VALIDATOR( &msg ) ); - - if( ( cmpdlg.ShowModal() != wxID_OK ) || msg.IsEmpty() ) - return NULL; // Aborted by user - - MODULE* module = aPcbFrame->CreateNewModule( msg ); - - // here the module is already in the BOARD, CreateNewModule() does that. - module->SetFPID( LIB_ID( std::string( "mw_inductor" ) ) ); - module->SetAttributes( MOD_VIRTUAL | MOD_CMS ); - module->ClearFlags(); - module->SetPosition( s_inductor_pattern.m_End ); - - // Generate segments - for( unsigned jj = 1; jj < buffer.size(); jj++ ) - { - EDGE_MODULE* PtSegm; - PtSegm = new EDGE_MODULE( module ); - PtSegm->SetStart( buffer[jj - 1] ); - PtSegm->SetEnd( buffer[jj] ); - PtSegm->SetWidth( s_inductor_pattern.m_Width ); - PtSegm->SetLayer( module->GetLayer() ); - PtSegm->SetShape( S_SEGMENT ); - PtSegm->SetStart0( PtSegm->GetStart() - module->GetPosition() ); - PtSegm->SetEnd0( PtSegm->GetEnd() - module->GetPosition() ); - module->GraphicalItems().PushBack( PtSegm ); - } - - // Place a pad on each end of coil. - pad = new D_PAD( module ); - - module->Pads().PushFront( pad ); - - pad->SetPadName( wxT( "1" ) ); - pad->SetPosition( s_inductor_pattern.m_End ); - pad->SetPos0( pad->GetPosition() - module->GetPosition() ); - - pad->SetSize( wxSize( s_inductor_pattern.m_Width, s_inductor_pattern.m_Width ) ); - - pad->SetLayerSet( LSET( module->GetLayer() ) ); - pad->SetAttribute( PAD_ATTRIB_SMD ); - pad->SetShape( PAD_SHAPE_CIRCLE ); - - D_PAD* newpad = new D_PAD( *pad ); - - module->Pads().Insert( newpad, pad->Next() ); - - pad = newpad; - pad->SetPadName( wxT( "2" ) ); - pad->SetPosition( s_inductor_pattern.m_Start ); - pad->SetPos0( pad->GetPosition() - module->GetPosition() ); - - // Modify text positions. - wxPoint refPos( ( s_inductor_pattern.m_Start.x + s_inductor_pattern.m_End.x ) / 2, - ( s_inductor_pattern.m_Start.y + s_inductor_pattern.m_End.y ) / 2 ); - - wxPoint valPos = refPos; - - refPos.y -= module->Reference().GetTextSize().y; - module->Reference().SetPosition( refPos ); - valPos.y += module->Value().GetTextSize().y; - module->Value().SetPosition( valPos ); - - module->CalculateBoundingBox(); - return module; -} - - -/** - * Function gen_arc - * generates an arc using arc approximation by lines: - * Center aCenter - * Angle "angle" (in 0.1 deg) - * @param aBuffer = a buffer to store points. - * @param aStartPoint = starting point of arc. - * @param aCenter = arc centre. - * @param a_ArcAngle = arc length in 0.1 degrees. - */ -static void gen_arc( std::vector & aBuffer, - wxPoint aStartPoint, - wxPoint aCenter, - int a_ArcAngle ) -{ - #define SEGM_COUNT_PER_360DEG 16 - wxPoint first_point = aStartPoint - aCenter; - int seg_count = ( ( abs( a_ArcAngle ) ) * SEGM_COUNT_PER_360DEG ) / 3600; - - if( seg_count == 0 ) - seg_count = 1; - - double increment_angle = (double) a_ArcAngle * M_PI / 1800 / seg_count; - - // Creates nb_seg point to approximate arc by segments: - for( int ii = 1; ii <= seg_count; ii++ ) - { - double rot_angle = increment_angle * ii; - double fcos = cos( rot_angle ); - double fsin = sin( rot_angle ); - wxPoint currpt; - - // Rotate current point: - currpt.x = KiROUND( ( first_point.x * fcos + first_point.y * fsin ) ); - currpt.y = KiROUND( ( first_point.y * fcos - first_point.x * fsin ) ); - - wxPoint corner = aCenter + currpt; - aBuffer.push_back( corner ); - } -} - - -/** - * Function BuildCornersList_S_Shape - * Create a path like a S-shaped coil - * @param aBuffer = a buffer where to store points (ends of segments) - * @param aStartPoint = starting point of the path - * @param aEndPoint = ending point of the path - * @param aLength = full length of the path - * @param aWidth = segment width - */ -int BuildCornersList_S_Shape( std::vector & aBuffer, - wxPoint aStartPoint, wxPoint aEndPoint, - int aLength, int aWidth ) -{ -/* We must determine: - * segm_count = number of segments perpendicular to the direction - * segm_len = length of a strand - * radius = radius of rounded parts of the coil - * stubs_len = length of the 2 stubs( segments parallel to the direction) - * connecting the start point to the start point of the S shape - * and the ending point to the end point of the S shape - * The equations are (assuming the area size of the entire shape is Size: - * Size.x = 2 * radius + segm_len - * Size.y = (segm_count + 2 ) * 2 * radius + 2 * stubs_len - * s_inductor_pattern.m_length = 2 * delta // connections to the coil - * + (segm_count-2) * segm_len // length of the strands except 1st and last - * + (segm_count) * (PI * radius) // length of rounded - * segm_len + / 2 - radius * 2) // length of 1st and last bit - * - * The constraints are: - * segm_count >= 2 - * radius < m_Size.x - * Size.y = (radius * 4) + (2 * stubs_len) - * segm_len > radius * 2 - * - * The calculation is conducted in the following way: - * first: - * segm_count = 2 - * radius = 4 * Size.x (arbitrarily fixed value) - * Then: - * Increasing the number of segments to the desired length - * (radius decreases if necessary) - */ - wxSize size; - - // This scale factor adjusts the arc length to handle - // the arc to segment approximation. - // because we use SEGM_COUNT_PER_360DEG segment to approximate a circle, - // the trace len must be corrected when calculated using arcs - // this factor adjust calculations and must be changed if SEGM_COUNT_PER_360DEG is modified - // because trace using segment is shorter the corresponding arc - // ADJUST_SIZE is the ratio between tline len and the arc len for an arc - // of 360/ADJUST_SIZE angle - #define ADJUST_SIZE 0.988 - - wxPoint pt = aEndPoint - aStartPoint; - double angle = -ArcTangente( pt.y, pt.x ); - int min_len = KiROUND( EuclideanNorm( pt ) ); - int segm_len = 0; // length of segments - int full_len; // full len of shape (sum of length of all segments + arcs) - - - /* Note: calculations are made for a vertical coil (more easy calculations) - * and after points are rotated to their actual position - * So the main direction is the Y axis. - * the 2 stubs are on the Y axis - * the others segments are parallel to the X axis. - */ - - // Calculate the size of area (for a vertical shape) - size.x = min_len / 2; - size.y = min_len; - - // Choose a reasonable starting value for the radius of the arcs. - int radius = std::min( aWidth * 5, size.x / 4 ); - - int segm_count; // number of full len segments - // the half size segments (first and last segment) are not counted here - int stubs_len = 0; // length of first or last segment (half size of others segments) - - for( segm_count = 0; ; segm_count++ ) - { - stubs_len = ( size.y - ( radius * 2 * (segm_count + 2 ) ) ) / 2; - - if( stubs_len < size.y / 10 ) // Reduce radius. - { - stubs_len = size.y / 10; - radius = ( size.y - (2 * stubs_len) ) / ( 2 * (segm_count + 2) ); - - if( radius < aWidth ) // Radius too small. - { - // Unable to create line: Requested length value is too large for room - return 0; - } - } - - segm_len = size.x - ( radius * 2 ); - full_len = 2 * stubs_len; // Length of coil connections. - full_len += segm_len * segm_count; // Length of full length segments. - full_len += KiROUND( ( segm_count + 2 ) * M_PI * ADJUST_SIZE * radius ); // Ard arcs len - full_len += segm_len - (2 * radius); // Length of first and last segments - // (half size segments len = segm_len/2 - radius). - - if( full_len >= aLength ) - break; - } - - // Adjust len by adjusting segm_len: - int delta_size = full_len - aLength; - - // reduce len of the segm_count segments + 2 half size segments (= 1 full size segment) - segm_len -= delta_size / (segm_count + 1); - - // Generate first line (the first stub) and first arc (90 deg arc) - pt = aStartPoint; - aBuffer.push_back( pt ); - pt.y += stubs_len; - aBuffer.push_back( pt ); - - wxPoint centre = pt; - centre.x -= radius; - gen_arc( aBuffer, pt, centre, -900 ); - pt = aBuffer.back(); - - int half_size_seg_len = segm_len / 2 - radius; - - if( half_size_seg_len ) - { - pt.x -= half_size_seg_len; - aBuffer.push_back( pt ); - } - - // Create shape. - int ii; - int sign = 1; - segm_count += 1; // increase segm_count to create the last half_size segment - - for( ii = 0; ii < segm_count; ii++ ) - { - int arc_angle; - - if( ii & 1 ) // odd order arcs are greater than 0 - sign = -1; - else - sign = 1; - - arc_angle = 1800 * sign; - centre = pt; - centre.y += radius; - gen_arc( aBuffer, pt, centre, arc_angle ); - pt = aBuffer.back(); - pt.x += segm_len * sign; - aBuffer.push_back( pt ); - } - - // The last point is false: - // it is the end of a full size segment, but must be - // the end of the second half_size segment. Change it. - sign *= -1; - aBuffer.back().x = aStartPoint.x + radius * sign; - - // create last arc - pt = aBuffer.back(); - centre = pt; - centre.y += radius; - gen_arc( aBuffer, pt, centre, 900 * sign ); - aBuffer.back(); - - // Rotate point - angle += 900; - - for( unsigned jj = 0; jj < aBuffer.size(); jj++ ) - { - RotatePoint( &aBuffer[jj].x, &aBuffer[jj].y, aStartPoint.x, aStartPoint.y, angle ); - } - - // push last point (end point) - aBuffer.push_back( aEndPoint ); - - return 1; -} - - MODULE* PCB_EDIT_FRAME::CreateMuWaveBaseFootprint( const wxString& aValue, int aTextSize, int aPadCount ) {