Adding Arcs to TRACKS

This expands the TRACKS class to also include ARCS
This commit is contained in:
Seth Hillbrand 2019-03-27 05:38:29 -07:00
parent c52b3ce0e4
commit 3af868e3d1
8 changed files with 232 additions and 5 deletions

View File

@ -134,6 +134,7 @@ loss_tangent
max_error
material
micro
mid
min_thickness
mirror
mod_edge_width

View File

@ -95,6 +95,7 @@ enum KICAD_T
PCB_MODULE_ZONE_AREA_T, ///< class ZONE_CONTAINER, managed by a footprint
PCB_TRACE_T, ///< class TRACK, a track segment (segment on a copper layer)
PCB_VIA_T, ///< class VIA, a via (like a track segment on a copper layer)
PCB_ARC_T, ///< class ARC, an arc track segment on a copper layer
PCB_MARKER_T, ///< class MARKER_PCB, a marker used to show something
PCB_DIMENSION_T, ///< class DIMENSION, a dimension (graphic item)
PCB_TARGET_T, ///< class PCB_TARGET, a target (graphic item)

View File

@ -4,7 +4,7 @@
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2012 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2019 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
@ -53,7 +53,8 @@ static bool ShowClearance( const PCB_DISPLAY_OPTIONS& aDisplOpts, const TRACK* a
{
// maybe return true for tracks and vias, not for zone segments
return IsCopperLayer( aTrack->GetLayer() )
&& ( aTrack->Type() == PCB_TRACE_T || aTrack->Type() == PCB_VIA_T )
&& ( aTrack->Type() == PCB_TRACE_T || aTrack->Type() == PCB_VIA_T
|| aTrack->Type() == PCB_ARC_T )
&& ( ( aDisplOpts.m_ShowTrackClearanceMode == PCB_DISPLAY_OPTIONS::SHOW_CLEARANCE_NEW_AND_EDITED_TRACKS_AND_VIA_AREAS
&& ( aTrack->IsDragging() || aTrack->IsMoving() || aTrack->IsNew() ) )
|| ( aDisplOpts.m_ShowTrackClearanceMode == PCB_DISPLAY_OPTIONS::SHOW_CLEARANCE_ALWAYS )
@ -75,7 +76,14 @@ EDA_ITEM* TRACK::Clone() const
}
VIA::VIA( BOARD_ITEM* aParent ) : TRACK( aParent, PCB_VIA_T )
EDA_ITEM* ARC::Clone() const
{
return new ARC( *this );
}
VIA::VIA( BOARD_ITEM* aParent ) :
TRACK( aParent, PCB_VIA_T )
{
SetViaType( VIATYPE::THROUGH );
m_BottomLayer = B_Cu;
@ -229,6 +237,14 @@ void TRACK::Rotate( const wxPoint& aRotCentre, double aAngle )
}
void ARC::Rotate( const wxPoint& aRotCentre, double aAngle )
{
RotatePoint( &m_Start, aRotCentre, aAngle );
RotatePoint( &m_End, aRotCentre, aAngle );
RotatePoint( &m_Mid, aRotCentre, aAngle );
}
void TRACK::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
{
if( aFlipLeftRight )
@ -247,6 +263,26 @@ void TRACK::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
}
void ARC::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
{
if( aFlipLeftRight )
{
m_Start.x = aCentre.x - ( m_Start.x - aCentre.x );
m_End.x = aCentre.x - ( m_End.x - aCentre.x );
m_Mid.x = aCentre.x - ( m_Mid.x - aCentre.x );
}
else
{
m_Start.y = aCentre.y - ( m_Start.y - aCentre.y );
m_End.y = aCentre.y - ( m_End.y - aCentre.y );
m_Mid.y = aCentre.y - ( m_Mid.y - aCentre.y );
}
int copperLayerCount = GetBoard()->GetCopperLayerCount();
SetLayer( FlipLayer( GetLayer(), copperLayerCount ) );
}
void VIA::Flip( const wxPoint& aCentre, bool aFlipLeftRight )
{
if( aFlipLeftRight )
@ -938,6 +974,22 @@ bool TRACK::HitTest( const wxPoint& aPosition, int aAccuracy ) const
}
bool ARC::HitTest( const wxPoint& aPosition, int aAccuracy ) const
{
int max_dist = aAccuracy + ( m_Width / 2 );
auto rel_start = EuclideanNorm( aPosition - m_Start );
auto rel_mid = EuclideanNorm( aPosition - m_Mid );
auto rel_end = EuclideanNorm( aPosition - m_End );
if( rel_start <= max_dist || rel_mid <= max_dist || rel_end <= max_dist )
return true;
//TODO: Calculate along arc
return false;
}
bool VIA::HitTest( const wxPoint& aPosition, int aAccuracy ) const
{
int max_dist = aAccuracy + ( m_Width / 2 );
@ -963,6 +1015,25 @@ bool TRACK::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
}
bool ARC::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
EDA_RECT box;
EDA_RECT arect = aRect;
arect.Inflate( aAccuracy );
box.SetOrigin( GetStart() );
box.Merge( GetMid() );
box.Merge( GetEnd() );
box.Inflate( GetWidth() / 2 );
if( aContained )
return arect.Contains( box );
else
return arect.Intersects( box );
}
bool VIA::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
EDA_RECT box;
@ -1005,6 +1076,13 @@ void TRACK::SwapData( BOARD_ITEM* aImage )
std::swap( *((TRACK*) this), *((TRACK*) aImage) );
}
void ARC::SwapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_ARC_T );
std::swap( *this, *static_cast<ARC*>( aImage ) );
}
void VIA::SwapData( BOARD_ITEM* aImage )
{
assert( aImage->Type() == PCB_VIA_T );

View File

@ -136,7 +136,7 @@ public:
* returns the length of the track using the hypotenuse calculation.
* @return double - the length of the track
*/
double GetLength() const
virtual double GetLength() const
{
return GetLineLength( m_Start, m_End );
}
@ -257,6 +257,63 @@ protected:
};
class ARC : public TRACK
{
public:
ARC( BOARD_ITEM* aParent ) : TRACK( aParent, PCB_ARC_T ){};
static inline bool ClassOf( const EDA_ITEM *aItem )
{
return aItem && PCB_ARC_T == aItem->Type();
}
virtual void Move( const wxPoint& aMoveVector ) override
{
m_Start += aMoveVector;
m_Mid += aMoveVector;
m_End += aMoveVector;
}
virtual void Rotate( const wxPoint& aRotCentre, double aAngle ) override;
virtual void Flip( const wxPoint& aCentre, bool aFlipLeftRight ) override;
void SetMid( const wxPoint& aMid ) { m_Mid = aMid; }
const wxPoint& GetMid() const { return m_Mid; }
virtual bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
virtual bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override;
wxString GetClass() const override
{
return wxT( "ARC" );
}
//TODO(snh): Add GetSelectMenuText() and GetMsgPanelInfoBase()
/**
* Function GetLength
* returns the length of the track using the hypotenuse calculation.
* @return double - the length of the track
*/
virtual double GetLength() const override
{
//TODO(snh): Add proper arc length calc
return GetLineLength( m_Start, m_Mid ) + GetLineLength( m_Mid, m_End );
}
EDA_ITEM* Clone() const override;
virtual void SwapData( BOARD_ITEM* aImage ) override;
protected:
private:
wxPoint m_Mid; ///< Arc mid point, halfway between start and end
};
class VIA : public TRACK
{
public:

View File

@ -1706,6 +1706,18 @@ void PCB_IO::format( TRACK* aTrack, int aNestLevel ) const
m_out->Quotew( m_board->GetLayerName( layer1 ) ).c_str(),
m_out->Quotew( m_board->GetLayerName( layer2 ) ).c_str() );
}
else if( aTrack->Type() == PCB_ARC_T )
{
const ARC* arc = static_cast<const ARC*>( aTrack );
m_out->Print( aNestLevel, "(arc (start %s) (mid %s) (end %s) (width %s)",
FormatInternalUnits( arc->GetStart() ).c_str(),
FormatInternalUnits( arc->GetMid() ).c_str(),
FormatInternalUnits( arc->GetEnd() ).c_str(),
FormatInternalUnits( arc->GetWidth() ).c_str() );
m_out->Print( 0, " (layer %s)", m_out->Quotew( aTrack->GetLayerName() ).c_str() );
}
else
{
m_out->Print( aNestLevel, "(segment (start %s) (end %s) (width %s)",

View File

@ -65,7 +65,8 @@ class TEXTE_PCB;
//#define SEXPR_BOARD_FILE_VERSION 20190905 // Add board physical stackup info in setup section
//#define SEXPR_BOARD_FILE_VERSION 20190907 // Keepout areas in footprints
//#define SEXPR_BOARD_FILE_VERSION 20191123 // pin function in pads
#define SEXPR_BOARD_FILE_VERSION 20200104 // pad property for fabrication
//#define SEXPR_BOARD_FILE_VERSION 20200104 // pad property for fabrication
#define SEXPR_BOARD_FILE_VERSION 20200119 // arcs in tracks
#define CTL_STD_LAYER_NAMES (1 << 0) ///< Use English Standard layer names
#define CTL_OMIT_NETS (1 << 1) ///< Omit pads net names (useless in library)

View File

@ -586,6 +586,10 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
m_board->Add( parseTRACK(), ADD_MODE::INSERT );
break;
case T_arc:
m_board->Add( parseARC(), ADD_INSERT );
break;
case T_via:
m_board->Add( parseVIA(), ADD_MODE::INSERT );
break;
@ -3349,6 +3353,77 @@ bool PCB_PARSER::parseD_PAD_option( D_PAD* aPad )
}
ARC* PCB_PARSER::parseARC()
{
wxCHECK_MSG( CurTok() == T_arc, NULL,
wxT( "Cannot parse " ) + GetTokenString( CurTok() ) + wxT( " as ARC." ) );
wxPoint pt;
T token;
std::unique_ptr<ARC> arc( new ARC( m_board ) );
for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{
if( token != T_LEFT )
Expecting( T_LEFT );
token = NextTok();
switch( token )
{
case T_start:
pt.x = parseBoardUnits( "start x" );
pt.y = parseBoardUnits( "start y" );
arc->SetStart( pt );
break;
case T_mid:
pt.x = parseBoardUnits( "mid x" );
pt.y = parseBoardUnits( "mid y" );
arc->SetMid( pt );
break;
case T_end:
pt.x = parseBoardUnits( "end x" );
pt.y = parseBoardUnits( "end y" );
arc->SetEnd( pt );
break;
case T_width:
arc->SetWidth( parseBoardUnits( "width" ) );
break;
case T_layer:
arc->SetLayer( parseBoardItemLayer() );
break;
case T_net:
if( !arc->SetNetCode( getNetCode( parseInt( "net number" ) ), /* aNoAssert */ true ) )
THROW_IO_ERROR( wxString::Format(
_( "Invalid net ID in\nfile: \"%s\"\nline: %d\noffset: %d" ),
GetChars( CurSource() ), CurLineNumber(), CurOffset() ) );
break;
case T_tstamp:
arc->SetTimeStamp( parseHex() );
break;
case T_status:
arc->SetStatus( static_cast<STATUS_FLAGS>( parseHex() ) );
break;
default:
Expecting( "start, mid, end, width, layer, net, tstamp, or status" );
}
NeedRIGHT();
}
return arc.release();
}
TRACK* PCB_PARSER::parseTRACK()
{
wxCHECK_MSG( CurTok() == T_segment, NULL,

View File

@ -39,6 +39,7 @@
#include <unordered_map>
class ARC;
class BOARD;
class BOARD_ITEM;
class BOARD_ITEM_CONTAINER;
@ -155,6 +156,7 @@ class PCB_PARSER : public PCB_LEXER
D_PAD* parseD_PAD( MODULE* aParent = NULL );
// Parse only the (option ...) inside a pad description
bool parseD_PAD_option( D_PAD* aPad );
ARC* parseARC();
TRACK* parseTRACK();
VIA* parseVIA();
ZONE_CONTAINER* parseZONE_CONTAINER( BOARD_ITEM_CONTAINER* aParent );