Added IPC2581 support

IPC2581 is a modern production file exchange system.  It provides
single-file data output for an entire board including BOM and netlist
information.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/1954
This commit is contained in:
Seth Hillbrand 2023-06-12 11:12:39 -07:00
parent 90a61b8d36
commit 75c6b0ab28
63 changed files with 73369 additions and 117 deletions

View File

@ -219,6 +219,8 @@ static const wxChar EnableGit[] = wxT( "EnableGit" );
static const wxChar EnableEeschemaPrintCairo[] = wxT( "EnableEeschemaPrintCairo" );
static const wxChar Enable2581[] = wxT( "Enable2581" );
/**
* The time in milliseconds to wait before displaying a disambiguation menu.
*/
@ -530,6 +532,11 @@ void ADVANCED_CFG::loadSettings( wxConfigBase& aCfg )
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::EnableEeschemaPrintCairo,
&m_EnableEeschemaPrintCairo, m_EnableEeschemaPrintCairo ) );
configParams.push_back( new PARAM_CFG_BOOL( true, AC_KEYS::Enable2581,
&m_Enable2581, m_Enable2581 ) );
// Special case for trace mask setting...we just grab them and set them immediately
// Because we even use wxLogTrace inside of advanced config
wxString traceMasks;

View File

@ -620,6 +620,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_24.png" ), 24, wxT( "light" ) );
@ -1013,6 +1014,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_dark_24.png" ), 24, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_dark_24.png" ), 24, wxT( "dark" ) );
@ -1405,6 +1407,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_16.png" ), 16, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_16.png" ), 16, wxT( "light" ) );
@ -1798,6 +1801,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_dark_16.png" ), 16, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_dark_16.png" ), 16, wxT( "dark" ) );
@ -2190,6 +2194,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_32.png" ), 32, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_32.png" ), 32, wxT( "light" ) );
@ -2583,6 +2588,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_dark_32.png" ), 32, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_dark_32.png" ), 32, wxT( "dark" ) );
@ -2975,6 +2981,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_48.png" ), 48, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_48.png" ), 48, wxT( "light" ) );
@ -3368,6 +3375,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_dark_48.png" ), 48, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_dark_48.png" ), 48, wxT( "dark" ) );
@ -3760,6 +3768,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_64.png" ), 64, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_64.png" ), 64, wxT( "light" ) );
@ -4153,6 +4162,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::post_gencad].emplace_back( BITMAPS::post_gencad, wxT( "post_gencad_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_gerber].emplace_back( BITMAPS::post_gerber, wxT( "post_gerber_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_rpt].emplace_back( BITMAPS::post_rpt, wxT( "post_rpt_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::post_xml].emplace_back( BITMAPS::post_xml, wxT( "post_xml_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::preference].emplace_back( BITMAPS::preference, wxT( "preference_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::print_button].emplace_back( BITMAPS::print_button, wxT( "print_button_dark_64.png" ), 64, wxT( "dark" ) );
aBitmapInfoCache[BITMAPS::project].emplace_back( BITMAPS::project, wxT( "project_dark_64.png" ), 64, wxT( "dark" ) );

View File

@ -94,8 +94,6 @@ wxString EDA_SHAPE::SHAPE_T_asString() const
case SHAPE_T::CIRCLE: return wxS( "S_CIRCLE" );
case SHAPE_T::POLY: return wxS( "S_POLYGON" );
case SHAPE_T::BEZIER: return wxS( "S_CURVE" );
// Synthetic value, but if we come across it then we're going to want to know.
case SHAPE_T::LAST: return wxS( "!S_LAST!" );
}
return wxEmptyString; // Just to quiet GCC.
@ -666,6 +664,23 @@ EDA_ANGLE EDA_SHAPE::GetArcAngle() const
}
bool EDA_SHAPE::IsClockwiseArc() const
{
if( m_shape == SHAPE_T::ARC )
{
VECTOR2D mid = GetArcMid();
double orient = ( mid.x - m_start.x ) * ( m_end.y - m_start.y )
- ( mid.y - m_start.y ) * ( m_end.x - m_start.x );
return orient < 0;
}
UNIMPLEMENTED_FOR( SHAPE_T_asString() );
return false;
}
void EDA_SHAPE::SetArcAngleAndEnd( const EDA_ANGLE& aAngle, bool aCheckNegativeAngle )
{
EDA_ANGLE angle( aAngle );

View File

@ -30,6 +30,7 @@
#include <pcb_textbox.h>
#include <pcb_shape.h>
#include <pad.h>
#include <pcb_track.h>
#include <macros.h>
#include <functional>
@ -74,15 +75,66 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
}
break;
case PCB_VIA_T:
{
const PCB_VIA* via = static_cast<const PCB_VIA*>( aItem );
ret = hash_val( via->GetWidth() );
hash_combine( ret, via->GetDrillValue() );
hash_combine( ret, via->TopLayer() );
hash_combine( ret, via->BottomLayer() );
for( PCB_LAYER_ID layer : via->GetLayerSet().Seq() )
hash_combine( ret, via->FlashLayer( layer ) );
break;
}
case PCB_PAD_T:
{
const PAD* pad = static_cast<const PAD*>( aItem );
ret = hash<int>{}( static_cast<int>( pad->GetShape() ) );
hash_combine( ret, pad->GetDrillShape() );
hash_combine( ret, pad->GetAttribute() );
if( pad->GetAttribute() == PAD_ATTRIB::PTH || pad->GetAttribute() == PAD_ATTRIB::NPTH )
{
hash_combine( ret, pad->GetDrillSizeX(), pad->GetDrillSizeY() );
hash_combine( ret, pad->GetDrillShape() );
for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
hash_combine( ret, pad->FlashLayer( layer ) );
}
hash_combine( ret, pad->GetSize().x, pad->GetSize().y );
hash_combine( ret, pad->GetOffset().x, pad->GetOffset().y );
hash_combine( ret, pad->GetDelta().x, pad->GetDelta().y );
switch( pad->GetShape() )
{
case PAD_SHAPE::CHAMFERED_RECT:
hash_combine( ret, pad->GetChamferPositions() );
hash_combine( ret, pad->GetChamferRectRatio() );
break;
case PAD_SHAPE::ROUNDRECT:
hash_combine( ret, pad->GetRoundRectCornerRadius() );
break;
case PAD_SHAPE::TRAPEZOID:
hash_combine( ret, pad->GetDelta().x, pad->GetDelta().y );
break;
case PAD_SHAPE::CUSTOM:
{
auto poly = pad->GetEffectivePolygon( ERROR_INSIDE );
for( int ii = 0; ii < poly->VertexCount(); ++ii )
{
VECTOR2I point = poly->CVertex( ii ) - pad->GetPosition();
hash_combine( ret, point.x, point.y );
}
break;
}
default:
break;
}
hash_combine( ret, hash_board_item( pad, aFlags ) );
@ -100,7 +152,7 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
if( aFlags & HASH_NET )
hash_combine( ret, pad->GetNetCode() );
}
break;
break;
case PCB_FIELD_T:
if( !( aFlags & HASH_REF ) && static_cast<const PCB_FIELD*>( aItem )->IsReference() )
@ -144,39 +196,57 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
hash_combine( ret, shape->GetShape() );
hash_combine( ret, shape->GetWidth() );
hash_combine( ret, shape->IsFilled() );
hash_combine( ret, shape->GetLineStyle() );
if( shape->GetShape() == SHAPE_T::ARC || shape->GetShape() == SHAPE_T::CIRCLE )
hash_combine( ret, shape->GetRadius() );
if( aFlags & HASH_POS )
{
VECTOR2I start = shape->GetStart();
VECTOR2I end = shape->GetEnd();
VECTOR2I center = shape->GetCenter();
std::vector<VECTOR2I> points;
points.push_back( shape->GetStart() );
points.push_back( shape->GetEnd() );
if( shape->GetShape() == SHAPE_T::CIRCLE )
points.push_back( shape->GetCenter() );
if( shape->GetShape() == SHAPE_T::ARC )
points.push_back( shape->GetArcMid() );
FOOTPRINT* parentFP = shape->GetParentFootprint();
if( shape->GetShape() == SHAPE_T::POLY )
{
const SHAPE_POLY_SET& poly = shape->GetPolyShape();
for( auto it = poly.CIterateWithHoles(); it; it++ )
points.push_back( *it );
}
if( shape->GetShape() == SHAPE_T::BEZIER )
{
points.push_back( shape->GetBezierC1() );
points.push_back( shape->GetBezierC2() );
}
if( parentFP && ( aFlags & REL_COORD ) )
{
start -= parentFP->GetPosition();
end -= parentFP->GetPosition();
center -= parentFP->GetPosition();
RotatePoint( start, -parentFP->GetOrientation() );
RotatePoint( end, -parentFP->GetOrientation() );
RotatePoint( center, -parentFP->GetOrientation() );
for( VECTOR2I& point : points )
{
point -= parentFP->GetPosition();
RotatePoint( point, -parentFP->GetOrientation() );
}
}
hash_combine( ret, start.x );
hash_combine( ret, start.y );
hash_combine( ret, end.x );
hash_combine( ret, end.y );
if( shape->GetShape() == SHAPE_T::ARC )
if( aFlags & REL_POS )
{
hash_combine( ret, center.x );
hash_combine( ret, center.y );
for( VECTOR2I& point : points )
point -= shape->GetPosition();
}
for( VECTOR2I& point : points )
hash_combine( ret, point.x, point.y );
}
}
break;
@ -200,6 +270,7 @@ size_t hash_fp_item( const EDA_ITEM* aItem, int aFlags )
hash_combine( ret, textbox->GetShape() );
hash_combine( ret, textbox->GetWidth() );
hash_combine( ret, textbox->GetLineStyle() );
if( aFlags & HASH_POS )
{

View File

@ -122,6 +122,21 @@ PROJECT_FILE::PROJECT_FILE( const wxString& aFullPath ) :
m_params.emplace_back( new PARAM_VIEWPORT( "board.viewports", &m_Viewports ) );
m_params.emplace_back( new PARAM_VIEWPORT3D( "board.3dviewports", &m_Viewports3D ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.internal_id",
&m_IP2581Bom.id, wxEmptyString ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mpn",
&m_IP2581Bom.MPN, wxEmptyString ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.mfg",
&m_IP2581Bom.mfg, wxEmptyString ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.distpn",
&m_IP2581Bom.distPN, wxEmptyString ) );
m_params.emplace_back( new PARAM<wxString>( "board.ipc2581.dist",
&m_IP2581Bom.dist, wxEmptyString ) );
}

View File

@ -101,7 +101,7 @@ void PROGRESS_REPORTER_BASE::AddPhases( int aNumPhases )
}
int PROGRESS_REPORTER_BASE::currentProgress() const
int PROGRESS_REPORTER_BASE::CurrentProgress() const
{
double current = ( 1.0 / (double) m_numPhases ) *
( (double) m_phase + ( (double) m_progress.load() / (double) m_maxProgress ) );

View File

@ -57,7 +57,7 @@ WX_PROGRESS_REPORTER::~WX_PROGRESS_REPORTER()
bool WX_PROGRESS_REPORTER::updateUI()
{
int cur = currentProgress();
int cur = CurrentProgress();
if( cur < 0 || cur > 1000 )
cur = 0;
@ -104,7 +104,7 @@ GAUGE_PROGRESS_REPORTER::GAUGE_PROGRESS_REPORTER( wxWindow* aParent, int aNumPha
bool GAUGE_PROGRESS_REPORTER::updateUI()
{
int cur = currentProgress();
int cur = CurrentProgress();
if( cur < 0 || cur > 1000 )
cur = 0;

View File

@ -181,6 +181,7 @@ const std::string KiCadFootprintFileExtension( "kicad_mod" );
const std::string SpecctraDsnFileExtension( "dsn" );
const std::string SpecctraSessionFileExtension( "ses" );
const std::string IpcD356FileExtension( "d356" );
const std::string Ipc2581FileExtension( "xml" );
const std::string WorkbookFileExtension( "wbk" );
const std::string PngFileExtension( "png" );

View File

@ -461,10 +461,6 @@ int SYMBOL_EDITOR_MOVE_TOOL::AlignElements( const TOOL_EVENT& aEvent )
doMoveItem( shape, newStart - shape->GetStart() );
break;
case SHAPE_T::LAST:
// Not a real shape
break;
}
}
else

View File

@ -288,6 +288,12 @@ public:
* When true, enable Eeschema printing using Cairo
*/
bool m_EnableEeschemaPrintCairo;
/**
* When true, enable output to 2581
*/
bool m_Enable2581;
///@}

View File

@ -454,6 +454,7 @@ enum class BITMAPS : unsigned int
post_gerber,
post_module,
post_rpt,
post_xml,
preference,
primitives_to_custom_pad,
print_button,

View File

@ -45,8 +45,7 @@ enum class SHAPE_T : int
ARC,
CIRCLE,
POLY,
BEZIER,
LAST ///< marker for list end
BEZIER
};
@ -311,6 +310,8 @@ public:
void SetSegmentAngle( const EDA_ANGLE& aAngle );
bool IsClockwiseArc() const;
/**
* @return the length of the segment using the hypotenuse calculation.
*/

View File

@ -44,11 +44,13 @@ enum HASH_FLAGS
///< use coordinates relative to the parent object
REL_COORD = 0x02,
HASH_ROT = 0x04,
HASH_LAYER = 0x08,
HASH_NET = 0x10,
HASH_REF = 0x20,
HASH_VALUE = 0x40,
///< use coordinates relative to the shape position
REL_POS = 0x04,
HASH_ROT = 0x08,
HASH_LAYER = 0x10,
HASH_NET = 0x20,
HASH_REF = 0x40,
HASH_VALUE = 0x80,
HASH_ALL = 0xff
};

View File

@ -124,6 +124,16 @@ enum class RATSNEST_MODE
VISIBLE ///< Ratsnest lines are drawn to items on visible layers only
};
///< BOM Data choices for IPC2581 export
struct IP2581_BOM
{
wxString mfg; ///< Manufacturer name column
wxString MPN; ///< Manufacturer part number column
wxString dist; ///< Distributor name column
wxString distPN; ///< Distributor part number column
wxString id; ///< Internal ID column
};
/**
* A saved set of layers that are visible.
*/

View File

@ -55,6 +55,7 @@ enum LAST_PATH_TYPE : unsigned int
LAST_PATH_POS_FILES,
LAST_PATH_SVG,
LAST_PATH_PLOT,
LAST_PATH_2581,
LAST_PATH_SIZE
};
@ -176,6 +177,8 @@ public:
std::vector<VIEWPORT> m_Viewports; /// List of stored viewports (pos + zoom)
std::vector<VIEWPORT3D> m_Viewports3D; /// List of stored 3D viewports (view matrixes)
struct IP2581_BOM m_IP2581Bom; /// IPC-2581 BOM settings
private:
/// An list of schematic sheets in this project
std::vector<FILE_INFO_PAIR> m_sheets;

View File

@ -107,8 +107,9 @@ public:
bool IsCancelled() const override { return m_cancelled; }
int CurrentProgress() const;
protected:
int currentProgress() const;
virtual bool updateUI() = 0;

View File

@ -166,6 +166,7 @@ extern const std::string DrawingSheetFileExtension;
extern const std::string SpecctraDsnFileExtension;
extern const std::string SpecctraSessionFileExtension;
extern const std::string IpcD356FileExtension;
extern const std::string Ipc2581FileExtension;
extern const std::string WorkbookFileExtension;
extern const std::string PngFileExtension;

View File

@ -0,0 +1,68 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 WX_FSTREAM_PROGRESS_H
#define WX_FSTREAM_PROGRESS_H
#include <wx/wfstream.h>
class wxFileOutputStreamWithProgress : public wxFileOutputStream
{
public:
wxFileOutputStreamWithProgress( const wxString& aFileName )
: wxFileOutputStream( aFileName )
{
}
wxFileOutputStreamWithProgress( wxFile& aFile )
: wxFileOutputStream( aFile )
{
}
wxFileOutputStreamWithProgress( int aFd )
: wxFileOutputStream( aFd )
{
}
virtual ~wxFileOutputStreamWithProgress() = default;
void SetProgressCallback( std::function<void( size_t )> aCallback )
{
m_callback = aCallback;
}
virtual size_t OnSysWrite( const void* aBuffer, size_t aSize ) override
{
size_t written = wxFileOutputStream::OnSysWrite( aBuffer, aSize );
if( m_callback )
m_callback( written );
return written;
}
private:
std::function<void( size_t )> m_callback;
};
#endif // WX_FSTREAM_PROGRESS_H

View File

@ -63,6 +63,8 @@ set( PCBNEW_DIALOGS
dialogs/dialog_enum_pads_base.cpp
dialogs/dialog_exchange_footprints.cpp
dialogs/dialog_exchange_footprints_base.cpp
dialogs/dialog_export_2581.cpp
dialogs/dialog_export_2581_base.cpp
dialogs/dialog_export_idf.cpp
dialogs/dialog_export_idf_base.cpp
dialogs/dialog_export_step.cpp
@ -598,8 +600,9 @@ add_subdirectory( plugins/cadstar )
add_subdirectory( plugins/easyeda )
add_subdirectory( plugins/easyedapro )
add_subdirectory( plugins/fabmaster )
add_subdirectory( plugins/ipc2581 )
set( PCBNEW_IO_LIBRARIES pcad2kicadpcb altium2pcbnew cadstar2pcbnew easyeda easyedapro fabmaster CACHE INTERNAL "")
set( PCBNEW_IO_LIBRARIES pcad2kicadpcb altium2pcbnew cadstar2pcbnew easyeda easyedapro fabmaster ipc2581 CACHE INTERNAL "")
# a very small program launcher for pcbnew_kiface
add_executable( pcbnew WIN32 MACOSX_BUNDLE

View File

@ -205,6 +205,7 @@ bool ConvertOutlineToPolygon( std::vector<PCB_SHAPE*>& aShapeList, SHAPE_POLY_SE
contours.emplace_back();
SHAPE_LINE_CHAIN& currContour = contours.back();
currContour.SetWidth( graphic->GetWidth() );
bool firstPt = true;
// Circles, rects and polygons are closed shapes unto themselves (and do not combine

View File

@ -0,0 +1,305 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <dialogs/dialog_export_2581.h>
#include <board.h>
#include <footprint.h>
#include <kiway_holder.h>
#include <pcb_edit_frame.h>
#include <pcbnew_settings.h>
#include <pgm_base.h>
#include <project.h>
#include <project/board_project_settings.h>
#include <project/project_file.h>
#include <settings/settings_manager.h>
#include <widgets/std_bitmap_button.h>
#include <set>
#include <vector>
#include <wx/filedlg.h>
static wxString s_oemColumn = wxEmptyString;
DIALOG_EXPORT_2581::DIALOG_EXPORT_2581( PCB_EDIT_FRAME* aParent ) :
DIALOG_EXPORT_2581_BASE( aParent ), m_parent( aParent )
{
m_browseButton->SetBitmap( KiBitmapBundle( BITMAPS::small_folder ) );
SetupStandardButtons( { { wxID_OK, _( "Export" ) },
{ wxID_CANCEL, _( "Close" ) } } );
wxString path = m_parent->GetLastPath( LAST_PATH_2581 );
if( path.IsEmpty() )
{
wxFileName brdFile( m_parent->GetBoard()->GetFileName() );
brdFile.SetExt( wxT( "xml" ) );
path = brdFile.GetFullPath();
}
m_outputFileName->SetValue( path );
m_textDistributor->SetSize( m_choiceDistPN->GetSize() );
// Now all widgets have the size fixed, call FinishDialogSettings
finishDialogSettings();
}
void DIALOG_EXPORT_2581::onBrowseClicked( wxCommandEvent& event )
{
// Build the absolute path of current output directory to preselect it in the file browser.
wxString path = ExpandEnvVarSubstitutions( m_outputFileName->GetValue(), &Prj() );
wxFileName fn( Prj().AbsolutePath( path ) );
wxString ipc_files = _( "IPC-2581 Files (*.xml)|*.xml" );
wxString compressed_files = _( "IPC-2581 Compressed Files (*.zip)|*.zip" );
wxFileDialog dlg( this, _( "Export IPC-2581 File" ), fn.GetPath(), fn.GetFullName(),
m_cbCompress->IsChecked() ? compressed_files : ipc_files,
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
if( dlg.ShowModal() == wxID_CANCEL )
return;
m_outputFileName->SetValue( dlg.GetPath() );
}
void DIALOG_EXPORT_2581::onOKClick( wxCommandEvent& event )
{
m_parent->SetLastPath( LAST_PATH_2581, m_outputFileName->GetValue() );
event.Skip();
}
void DIALOG_EXPORT_2581::onCompressCheck( wxCommandEvent& event )
{
if( m_cbCompress->GetValue() )
{
wxFileName fn = m_outputFileName->GetValue();
fn.SetExt( "zip" );
m_outputFileName->SetValue( fn.GetFullPath() );
}
else
{
wxFileName fn = m_outputFileName->GetValue();
fn.SetExt( "xml" );
m_outputFileName->SetValue( fn.GetFullPath() );
}
}
void DIALOG_EXPORT_2581::onMfgPNChange( wxCommandEvent& event )
{
if( event.GetSelection() == 0 )
{
m_choiceMfg->Enable( false );
}
else
{
m_choiceMfg->Enable( true );
// Don't try to guess the manufacturer if the user has already selected one
if( m_choiceMfg->GetSelection() > 0 )
return;
int it = 0;
if( it = m_choiceMfg->FindString( wxT( "manufacturer" ) ); it != wxNOT_FOUND )
{
m_choiceMfg->Select( it );
}
else if( it = m_choiceMfg->FindString( _( "manufacturer" ) ); it != wxNOT_FOUND )
{
m_choiceMfg->Select( it );
}
else if( it = m_choiceMfg->FindString( wxT( "mfg" ) ); it != wxNOT_FOUND )
{
m_choiceMfg->Select( it );
}
else if( it = m_choiceMfg->FindString( _( "mfg" ) ); it != wxNOT_FOUND )
{
m_choiceMfg->Select( it );
}
}
}
void DIALOG_EXPORT_2581::onDistPNChange( wxCommandEvent& event )
{
if( event.GetSelection() == 0 )
{
m_textDistributor->Enable( false );
m_textDistributor->SetValue( _( "N/A" ) );
}
else
{
m_textDistributor->Enable( true );
// Don't try to guess the distributor if the user has already selected one
if( m_textDistributor->GetValue() != _( "N/A" ) )
return;
wxString dist = m_choiceDistPN->GetStringSelection();
dist.MakeUpper();
// Try to guess the distributor from the part number column
if( dist.Contains( wxT( "DIGIKEY" ) ) )
{
m_textDistributor->SetValue( wxT( "Digi-Key" ) );
}
else if( dist.Contains( wxT( "DIGI-KEY" ) ) )
{
m_textDistributor->SetValue( wxT( "Digi-Key" ) );
}
else if( dist.Contains( wxT( "MOUSER" ) ) )
{
m_textDistributor->SetValue( wxT( "Mouser" ) );
}
else if( dist.Contains( wxT( "NEWARK" ) ) )
{
m_textDistributor->SetValue( wxT( "Newark" ) );
}
else if( dist.Contains( wxT( "RS COMPONENTS" ) ) )
{
m_textDistributor->SetValue( wxT( "RS Components" ) );
}
else if( dist.Contains( wxT( "FARNELL" ) ) )
{
m_textDistributor->SetValue( wxT( "Farnell" ) );
}
else if( dist.Contains( wxT( "ARROW" ) ) )
{
m_textDistributor->SetValue( wxT( "Arrow" ) );
}
else if( dist.Contains( wxT( "AVNET" ) ) )
{
m_textDistributor->SetValue( wxT( "Avnet" ) );
}
else if( dist.Contains( wxT( "TME" ) ) )
{
m_textDistributor->SetValue( wxT( "TME" ) );
}
else if( dist.Contains( wxT( "LCSC" ) ) )
{
m_textDistributor->SetValue( wxT( "LCSC" ) );
}
}
}
bool DIALOG_EXPORT_2581::TransferDataToWindow()
{
PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
std::set<wxString> options;
BOARD* board = m_parent->GetBoard();
for( FOOTPRINT* fp : board->Footprints() )
{
for( PCB_FIELD* field : fp->GetFields() )
options.insert( field->GetName() );
}
m_choiceUnits->SetSelection( cfg->m_Export2581.units );
m_precision->SetValue( cfg->m_Export2581.precision );
m_versionChoice->SetSelection( cfg->m_Export2581.version );
m_cbCompress->SetValue( cfg->m_Export2581.compress );
wxCommandEvent dummy;
onCompressCheck( dummy );
std::vector<wxString> items( options.begin(), options.end() );
m_oemRef->Append( items );
m_choiceMPN->Append( items );
m_choiceMfg->Append( items );
m_choiceDistPN->Append( items );
m_oemRef->SetStringSelection( s_oemColumn );
PROJECT_FILE& prj = Prj().GetProjectFile();
if( !m_choiceMPN->SetStringSelection( prj.m_IP2581Bom.id ) )
m_choiceMPN->SetSelection( 0 );
if( m_choiceMPN->SetStringSelection( prj.m_IP2581Bom.MPN ) )
{
m_choiceMfg->Enable( true );
if( !m_choiceMfg->SetStringSelection( prj.m_IP2581Bom.mfg ) )
m_choiceMfg->SetSelection( 0 );
}
else
{
m_choiceMPN->SetSelection( 0 );
m_choiceMfg->SetSelection( 0 );
m_choiceMfg->Enable( false );
}
if( m_choiceDistPN->SetStringSelection( prj.m_IP2581Bom.distPN ) )
{
m_textDistributor->Enable( true );
// The combo box selection can be fixed, so any value can be entered
if( !prj.m_IP2581Bom.distPN.empty() )
{
m_textDistributor->SetValue( prj.m_IP2581Bom.dist );
}
else
{
wxCommandEvent evt;
onDistPNChange( evt );
}
}
else
{
m_choiceDistPN->SetSelection( 0 );
m_textDistributor->SetValue( _( "N/A" ) );
m_textDistributor->Enable( false );
}
return true;
}
bool DIALOG_EXPORT_2581::TransferDataFromWindow()
{
PCBNEW_SETTINGS* cfg = Pgm().GetSettingsManager().GetAppSettings<PCBNEW_SETTINGS>();
cfg->m_Export2581.units = m_choiceUnits->GetSelection();
cfg->m_Export2581.precision = m_precision->GetValue();
cfg->m_Export2581.version = m_versionChoice->GetSelection();
cfg->m_Export2581.compress = m_cbCompress->GetValue();
PROJECT_FILE& prj = Prj().GetProjectFile();
wxString empty;
prj.m_IP2581Bom.id = GetOEM();
prj.m_IP2581Bom.mfg = GetMfg();
prj.m_IP2581Bom.MPN = GetMPN();
prj.m_IP2581Bom.distPN = GetDistPN();
prj.m_IP2581Bom.dist = GetDist();
s_oemColumn = m_oemRef->GetStringSelection();
return true;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,113 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef IPC2581_EXPORT_DIALOG_H
#define IPC2581_EXPORT_DIALOG_H
#include "dialog_export_2581_base.h"
class PCB_EDIT_FRAME;
class DIALOG_EXPORT_2581 : public DIALOG_EXPORT_2581_BASE
{
public:
DIALOG_EXPORT_2581( PCB_EDIT_FRAME* aParent );
wxString GetOutputPath() const
{
return m_outputFileName->GetValue();
}
wxString GetUnitsString() const
{
if( m_choiceUnits->GetSelection() == 0 )
return wxT( "mm" );
else
return wxT( "inch" );
}
wxString GetPrecision() const
{
return wxString::Format( "%d", m_precision->GetValue() );
}
char GetVersion() const
{
return m_versionChoice->GetSelection() == 0 ? 'B' : 'C';
}
wxString GetOEM() const
{
if( m_oemRef->GetSelection() == 0 )
return wxEmptyString;
else
return m_oemRef->GetStringSelection();
}
bool GetCompress() const
{
return m_cbCompress->GetValue();
}
wxString GetMPN() const
{
if( !m_choiceMPN->IsEnabled() || m_choiceMPN->GetSelection() == 0 )
return wxEmptyString;
else
return m_choiceMPN->GetStringSelection();
}
wxString GetMfg() const
{
if( !m_choiceMfg->IsEnabled() || m_choiceMfg->GetSelection() == 0 )
return wxEmptyString;
else
return m_choiceMfg->GetStringSelection();
}
wxString GetDistPN() const
{
if( !m_choiceDistPN->IsEnabled() || m_choiceDistPN->GetSelection() == 0 )
return wxEmptyString;
else
return m_choiceDistPN->GetStringSelection();
}
wxString GetDist() const
{
if( !m_textDistributor->IsEnabled() || m_textDistributor->GetValue() == _( "N/A" ) )
return wxEmptyString;
else
return m_textDistributor->GetValue();
}
private:
void onBrowseClicked( wxCommandEvent& event ) override;
void onOKClick( wxCommandEvent& event ) override;
void onCompressCheck( wxCommandEvent& event ) override;
void onMfgPNChange( wxCommandEvent& event ) override;
void onDistPNChange( wxCommandEvent& event ) override;
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
PCB_EDIT_FRAME* m_parent;
};
#endif // IPC2581_EXPORT_DIALOG_H

View File

@ -0,0 +1,202 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf0)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "widgets/std_bitmap_button.h"
#include "dialog_export_2581_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_EXPORT_2581_BASE::DIALOG_EXPORT_2581_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxDefaultSize, wxDefaultSize );
wxBoxSizer* bMainSizer;
bMainSizer = new wxBoxSizer( wxVERTICAL );
bSizerTop = new wxBoxSizer( wxHORIZONTAL );
m_lblBrdFile = new wxStaticText( this, wxID_ANY, _("File:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblBrdFile->Wrap( -1 );
bSizerTop->Add( m_lblBrdFile, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_outputFileName = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_outputFileName->SetToolTip( _("Enter a filename if you do not want to use default file names\nCan be used only when printing the current sheet") );
m_outputFileName->SetMinSize( wxSize( 350,-1 ) );
bSizerTop->Add( m_outputFileName, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_browseButton = new STD_BITMAP_BUTTON( this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize( -1,-1 ), wxBU_AUTODRAW|0 );
bSizerTop->Add( m_browseButton, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT, 5 );
bMainSizer->Add( bSizerTop, 0, wxBOTTOM|wxEXPAND|wxTOP, 15 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
wxStaticBoxSizer* sbSizer1;
sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("File Format") ), wxVERTICAL );
wxFlexGridSizer* fgSizer;
fgSizer = new wxFlexGridSizer( 0, 2, 0, 0 );
fgSizer->AddGrowableCol( 1 );
fgSizer->SetFlexibleDirection( wxBOTH );
fgSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_lblUnits = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Units:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblUnits->Wrap( -1 );
fgSizer->Add( m_lblUnits, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
wxString m_choiceUnitsChoices[] = { _("Millimeters"), _("Inches") };
int m_choiceUnitsNChoices = sizeof( m_choiceUnitsChoices ) / sizeof( wxString );
m_choiceUnits = new wxChoice( sbSizer1->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceUnitsNChoices, m_choiceUnitsChoices, 0 );
m_choiceUnits->SetSelection( 0 );
fgSizer->Add( m_choiceUnits, 0, wxALL|wxEXPAND, 5 );
m_lblPrecision = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Precision:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblPrecision->Wrap( -1 );
m_lblPrecision->SetToolTip( _("The number of values following the decimal separator") );
fgSizer->Add( m_lblPrecision, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
m_precision = new wxSpinCtrl( sbSizer1->GetStaticBox(), wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 2, 16, 3 );
m_precision->SetToolTip( _("The number of values following the decimal separator") );
fgSizer->Add( m_precision, 0, wxALL|wxEXPAND, 5 );
m_lblVersion = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Version:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblVersion->Wrap( -1 );
fgSizer->Add( m_lblVersion, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxString m_versionChoiceChoices[] = { _("B"), _("C") };
int m_versionChoiceNChoices = sizeof( m_versionChoiceChoices ) / sizeof( wxString );
m_versionChoice = new wxChoice( sbSizer1->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_versionChoiceNChoices, m_versionChoiceChoices, 0 );
m_versionChoice->SetSelection( 1 );
fgSizer->Add( m_versionChoice, 0, wxALL|wxEXPAND, 5 );
m_cbCompress = new wxCheckBox( sbSizer1->GetStaticBox(), wxID_ANY, _("Compress Output"), wxDefaultPosition, wxDefaultSize, 0 );
m_cbCompress->SetToolTip( _("Compress output into 'zip' file") );
fgSizer->Add( m_cbCompress, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
sbSizer1->Add( fgSizer, 3, wxEXPAND|wxALL, 5 );
bSizer3->Add( sbSizer1, 1, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 10 );
wxStaticBoxSizer* sbSizer2;
sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("BOM Columns") ), wxVERTICAL );
wxFlexGridSizer* fgSizer4;
fgSizer4 = new wxFlexGridSizer( 0, 2, 0, 0 );
fgSizer4->SetFlexibleDirection( wxBOTH );
fgSizer4->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_lblOEM = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Internal ID:"), wxDefaultPosition, wxDefaultSize, 0 );
m_lblOEM->Wrap( -1 );
m_lblOEM->SetToolTip( _("Part ID number used internally during design.\nThis number must be unique to each part.") );
fgSizer4->Add( m_lblOEM, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
wxString m_oemRefChoices[] = { _("Generate Unique") };
int m_oemRefNChoices = sizeof( m_oemRefChoices ) / sizeof( wxString );
m_oemRef = new wxChoice( sbSizer2->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_oemRefNChoices, m_oemRefChoices, 0 );
m_oemRef->SetSelection( 0 );
m_oemRef->SetToolTip( _("Part ID number used internally during design.\nThis number must be unique to each part.") );
fgSizer4->Add( m_oemRef, 0, wxALL|wxEXPAND, 5 );
m_staticText6 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Manufacturer P/N:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText6->Wrap( -1 );
m_staticText6->SetToolTip( _("Column containing the manufacturer part number") );
fgSizer4->Add( m_staticText6, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
wxString m_choiceMPNChoices[] = { _("Omit") };
int m_choiceMPNNChoices = sizeof( m_choiceMPNChoices ) / sizeof( wxString );
m_choiceMPN = new wxChoice( sbSizer2->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceMPNNChoices, m_choiceMPNChoices, 0 );
m_choiceMPN->SetSelection( 0 );
m_choiceMPN->SetToolTip( _("Column containing the manufacturer part number") );
fgSizer4->Add( m_choiceMPN, 0, wxALL|wxEXPAND, 5 );
m_staticText7 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Manufacturer:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText7->Wrap( -1 );
fgSizer4->Add( m_staticText7, 0, wxALIGN_CENTER_VERTICAL|wxALL|wxEXPAND, 5 );
wxString m_choiceMfgChoices[] = { _("N/A") };
int m_choiceMfgNChoices = sizeof( m_choiceMfgChoices ) / sizeof( wxString );
m_choiceMfg = new wxChoice( sbSizer2->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceMfgNChoices, m_choiceMfgChoices, 0 );
m_choiceMfg->SetSelection( 0 );
m_choiceMfg->Enable( false );
fgSizer4->Add( m_choiceMfg, 0, wxALL|wxEXPAND, 5 );
m_staticText8 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Distributor P/N:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText8->Wrap( -1 );
fgSizer4->Add( m_staticText8, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxString m_choiceDistPNChoices[] = { _("Omit") };
int m_choiceDistPNNChoices = sizeof( m_choiceDistPNChoices ) / sizeof( wxString );
m_choiceDistPN = new wxChoice( sbSizer2->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, m_choiceDistPNNChoices, m_choiceDistPNChoices, 0 );
m_choiceDistPN->SetSelection( 0 );
m_choiceDistPN->SetToolTip( _("Column containing the distributor part number") );
fgSizer4->Add( m_choiceDistPN, 0, wxALL|wxEXPAND, 5 );
m_staticText9 = new wxStaticText( sbSizer2->GetStaticBox(), wxID_ANY, _("Distributor:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText9->Wrap( -1 );
fgSizer4->Add( m_staticText9, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_textDistributor = new wxTextCtrl( sbSizer2->GetStaticBox(), wxID_ANY, _("N/A"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer4->Add( m_textDistributor, 0, wxALL|wxEXPAND, 5 );
sbSizer2->Add( fgSizer4, 1, wxEXPAND, 5 );
bSizer3->Add( sbSizer2, 1, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 10 );
bMainSizer->Add( bSizer3, 0, wxEXPAND, 5 );
m_stdButtons = new wxStdDialogButtonSizer();
m_stdButtonsOK = new wxButton( this, wxID_OK );
m_stdButtons->AddButton( m_stdButtonsOK );
m_stdButtonsCancel = new wxButton( this, wxID_CANCEL );
m_stdButtons->AddButton( m_stdButtonsCancel );
m_stdButtons->Realize();
bMainSizer->Add( m_stdButtons, 0, wxEXPAND|wxALL, 5 );
this->SetSizer( bMainSizer );
this->Layout();
bMainSizer->Fit( this );
this->Centre( wxBOTH );
// Connect Events
m_browseButton->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onBrowseClicked ), NULL, this );
m_cbCompress->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onCompressCheck ), NULL, this );
m_choiceMPN->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onMfgPNChange ), NULL, this );
m_choiceDistPN->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onDistPNChange ), NULL, this );
m_stdButtonsOK->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onOKClick ), NULL, this );
}
DIALOG_EXPORT_2581_BASE::~DIALOG_EXPORT_2581_BASE()
{
// Disconnect Events
m_browseButton->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onBrowseClicked ), NULL, this );
m_cbCompress->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onCompressCheck ), NULL, this );
m_choiceMPN->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onMfgPNChange ), NULL, this );
m_choiceDistPN->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onDistPNChange ), NULL, this );
m_stdButtonsOK->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_EXPORT_2581_BASE::onOKClick ), NULL, this );
}

View File

@ -0,0 +1,86 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.0.0-0-g0efcecf0)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class STD_BITMAP_BUTTON;
#include "dialog_shim.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/bmpbuttn.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/button.h>
#include <wx/sizer.h>
#include <wx/choice.h>
#include <wx/spinctrl.h>
#include <wx/checkbox.h>
#include <wx/statbox.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_EXPORT_2581_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_EXPORT_2581_BASE : public DIALOG_SHIM
{
private:
protected:
wxBoxSizer* bSizerTop;
wxStaticText* m_lblBrdFile;
wxTextCtrl* m_outputFileName;
STD_BITMAP_BUTTON* m_browseButton;
wxStaticText* m_lblUnits;
wxChoice* m_choiceUnits;
wxStaticText* m_lblPrecision;
wxSpinCtrl* m_precision;
wxStaticText* m_lblVersion;
wxChoice* m_versionChoice;
wxCheckBox* m_cbCompress;
wxStaticText* m_lblOEM;
wxChoice* m_oemRef;
wxStaticText* m_staticText6;
wxChoice* m_choiceMPN;
wxStaticText* m_staticText7;
wxChoice* m_choiceMfg;
wxStaticText* m_staticText8;
wxChoice* m_choiceDistPN;
wxStaticText* m_staticText9;
wxTextCtrl* m_textDistributor;
wxStdDialogButtonSizer* m_stdButtons;
wxButton* m_stdButtonsOK;
wxButton* m_stdButtonsCancel;
// Virtual event handlers, override them in your derived class
virtual void onBrowseClicked( wxCommandEvent& event ) { event.Skip(); }
virtual void onCompressCheck( wxCommandEvent& event ) { event.Skip(); }
virtual void onMfgPNChange( wxCommandEvent& event ) { event.Skip(); }
virtual void onDistPNChange( wxCommandEvent& event ) { event.Skip(); }
virtual void onOKClick( wxCommandEvent& event ) { event.Skip(); }
public:
DIALOG_EXPORT_2581_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Export IPC-2581"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxDEFAULT_DIALOG_STYLE );
~DIALOG_EXPORT_2581_BASE();
};

View File

@ -28,6 +28,7 @@
#include <confirm.h>
#include <core/arraydim.h>
#include <core/thread_pool.h>
#include <gestfich.h>
#include <pcb_edit_frame.h>
#include <board_design_settings.h>
@ -58,6 +59,7 @@
#include <project/net_settings.h>
#include <plugins/cadstar/cadstar_pcb_archive_plugin.h>
#include <plugins/kicad/pcb_plugin.h>
#include <dialogs/dialog_export_2581.h>
#include <dialogs/dialog_imported_layers.h>
#include <dialogs/dialog_import_choose_project.h>
#include <plugins/common/plugin_common_choose_project.h>
@ -70,8 +72,11 @@
#include <kiplatform/io.h>
#include <wx/stdpaths.h>
#include <wx/ffile.h>
#include <wx/filedlg.h>
#include <wx/txtstrm.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include "widgets/filedlg_hook_save_project.h"
@ -1220,3 +1225,131 @@ bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType,
return false;
}
void PCB_EDIT_FRAME::GenIPC2581File( wxCommandEvent& event )
{
DIALOG_EXPORT_2581 dlg( this );
if( dlg.ShowModal() != wxID_OK )
return;
wxFileName pcbFileName = dlg.GetOutputPath();
// Write through symlinks, don't replace them
WX_FILENAME::ResolvePossibleSymlinks( pcbFileName );
if( pcbFileName.GetName().empty() )
{
DisplayError( this, _( "The board must be saved before generating IPC2581 file." ) );
return;
}
if( !IsWritable( pcbFileName ) )
{
wxString msg = wxString::Format( _( "Insufficient permissions to write file '%s'." ),
pcbFileName.GetFullPath() );
DisplayError( this, msg );
return;
}
wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
wxString upperTxt;
wxString lowerTxt;
WX_PROGRESS_REPORTER reporter( this, _( "Generating IPC2581 file" ), 5 );
STRING_UTF8_MAP props;
props["units"] = dlg.GetUnitsString();
props["sigfig"] = dlg.GetPrecision();
props["version"] = dlg.GetVersion();
props["OEMRef"] = dlg.GetOEM();
props["mpn"] = dlg.GetMPN();
props["mfg"] = dlg.GetMfg();
props["dist"] = dlg.GetDist();
props["distpn"] = dlg.GetDistPN();
auto saveFile = [&]() -> bool
{
try
{
PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::IPC2581 ) );
pi->SaveBoard( tempFile, GetBoard(), &props, &reporter );
return true;
}
catch( const IO_ERROR& ioe )
{
DisplayError( this, wxString::Format( _( "Error generating IPC2581 file '%s'.\n%s" ),
pcbFileName.GetFullPath(), ioe.What() ) );
lowerTxt.Printf( _( "Failed to create temporary file '%s'." ), tempFile );
SetMsgPanel( upperTxt, lowerTxt );
// In case we started a file but didn't fully write it, clean up
wxRemoveFile( tempFile );
return false;
}
};
thread_pool& tp = GetKiCadThreadPool();
auto ret = tp.submit( saveFile );
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
while( status != std::future_status::ready )
{
reporter.KeepRefreshing();
status = ret.wait_for( std::chrono::milliseconds( 250 ) );
}
try
{
if( !ret.get() )
return;
}
catch(const std::exception& e)
{
wxLogError( "Exception in IPC2581 generation: %s", e.what() );
return;
}
// Preserve the permissions of the current file
KIPLATFORM::IO::DuplicatePermissions( pcbFileName.GetFullPath(), tempFile );
if( dlg.GetCompress() )
{
wxFileName tempfn = pcbFileName;
tempfn.SetExt( Ipc2581FileExtension );
wxFileName zipfn = tempFile;
zipfn.SetExt( "zip" );
wxFFileOutputStream fnout( zipfn.GetFullPath() );
wxZipOutputStream zip( fnout );
wxFFileInputStream fnin( tempFile );
zip.PutNextEntry( tempfn.GetFullName() );
fnin.Read( zip );
zip.Close();
fnout.Close();
wxRemoveFile( tempFile );
tempFile = zipfn.GetFullPath();
}
// If save succeeded, replace the original with what we just wrote
if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
{
DisplayError( this, wxString::Format( _( "Error generating IPC2581 file '%s'.\n"
"Failed to rename temporary file '%s." ),
pcbFileName.GetFullPath(),
tempFile ) );
lowerTxt.Printf( _( "Failed to rename temporary file '%s'." ),
tempFile );
SetMsgPanel( upperTxt, lowerTxt );
}
}

View File

@ -293,6 +293,9 @@ bool FOOTPRINT::HasFieldByName( const wxString& aFieldName ) const
PCB_FIELD* FOOTPRINT::GetFieldByName( const wxString& aFieldName )
{
if( aFieldName.empty() )
return nullptr;
for( PCB_FIELD* field : m_fields )
{
if( field->GetName() == aFieldName )
@ -2499,14 +2502,24 @@ void FOOTPRINT::BuildCourtyardCaches( OUTLINE_ERROR_HANDLER* aErrorHandler )
// Collect items:
std::vector<PCB_SHAPE*> list_front;
std::vector<PCB_SHAPE*> list_back;
std::map<int, int> front_width_histogram;
std::map<int, int> back_width_histogram;
for( BOARD_ITEM* item : GraphicalItems() )
{
if( item->GetLayer() == B_CrtYd && item->Type() == PCB_SHAPE_T )
list_back.push_back( static_cast<PCB_SHAPE*>( item ) );
{
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
list_back.push_back( shape );
back_width_histogram[ shape->GetStroke().GetWidth() ]++;
}
if( item->GetLayer() == F_CrtYd && item->Type() == PCB_SHAPE_T )
list_front.push_back( static_cast<PCB_SHAPE*>( item ) );
{
PCB_SHAPE* shape = static_cast<PCB_SHAPE*>( item );
list_front.push_back( shape );
front_width_histogram[ shape->GetStroke().GetWidth() ]++;
}
}
if( !list_front.size() && !list_back.size() )
@ -2522,6 +2535,18 @@ void FOOTPRINT::BuildCourtyardCaches( OUTLINE_ERROR_HANDLER* aErrorHandler )
m_courtyard_cache_front.Inflate( -1, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, maxError );
m_courtyard_cache_front.CacheTriangulation( false );
auto max = std::max_element( front_width_histogram.begin(), front_width_histogram.end(),
[]( const std::pair<int, int>& a, const std::pair<int, int>& b )
{
return a.second < b.second;
} );
int width = max->first;
if( width == 0 )
width = DEFAULT_COURTYARD_WIDTH;
if( m_courtyard_cache_front.OutlineCount() > 0 )
m_courtyard_cache_front.Outline( 0 ).SetWidth( width );
}
else
{
@ -2535,6 +2560,18 @@ void FOOTPRINT::BuildCourtyardCaches( OUTLINE_ERROR_HANDLER* aErrorHandler )
m_courtyard_cache_back.Inflate( -1, CORNER_STRATEGY::CHAMFER_ACUTE_CORNERS, maxError );
m_courtyard_cache_back.CacheTriangulation( false );
auto max = std::max_element( back_width_histogram.begin(), back_width_histogram.end(),
[]( const std::pair<int, int>& a, const std::pair<int, int>& b )
{
return a.second < b.second;
} );
int width = max->first;
if( width == 0 )
width = DEFAULT_COURTYARD_WIDTH;
if( m_courtyard_cache_back.OutlineCount() > 0 )
m_courtyard_cache_back.Outline( 0 ).SetWidth( width );
}
else
{
@ -2999,51 +3036,78 @@ double FOOTPRINT::Similarity( const BOARD_ITEM& aOther ) const
}
#define TEST( a, b ) { if( a != b ) return a < b; }
#define TEST_PT( a, b ) { if( a.x != b.x ) return a.x < b.x; if( a.y != b.y ) return a.y < b.y; }
bool FOOTPRINT::cmp_drawings::operator()( const BOARD_ITEM* itemA, const BOARD_ITEM* itemB ) const
{
TEST( itemA->Type(), itemB->Type() );
TEST( itemA->GetLayer(), itemB->GetLayer() );
if( itemA->Type() != itemB->Type() )
return itemA->Type() < itemB->Type();
if( itemA->GetLayer() != itemB->GetLayer() )
return itemA->GetLayer() < itemB->GetLayer();
if( itemA->Type() == PCB_SHAPE_T )
{
const PCB_SHAPE* dwgA = static_cast<const PCB_SHAPE*>( itemA );
const PCB_SHAPE* dwgB = static_cast<const PCB_SHAPE*>( itemB );
TEST( dwgA->GetShape(), dwgB->GetShape() );
if( dwgA->GetShape() != dwgB->GetShape() )
return dwgA->GetShape() < dwgB->GetShape();
// GetStart() and GetEnd() have no meaning with polygons.
// We cannot use them for sorting polygons
if( dwgA->GetShape() != SHAPE_T::POLY )
{
TEST_PT( dwgA->GetStart(), dwgB->GetStart() );
TEST_PT( dwgA->GetEnd(), dwgB->GetEnd() );
if( dwgA->GetStart().x != dwgB->GetStart().x )
return dwgA->GetStart().x < dwgB->GetStart().x;
if( dwgA->GetStart().y != dwgB->GetStart().y )
return dwgA->GetStart().y < dwgB->GetStart().y;
if( dwgA->GetEnd().x != dwgB->GetEnd().x )
return dwgA->GetEnd().x < dwgB->GetEnd().x;
if( dwgA->GetEnd().y != dwgB->GetEnd().y )
return dwgA->GetEnd().y < dwgB->GetEnd().y;
}
if( dwgA->GetShape() == SHAPE_T::ARC )
{
TEST_PT( dwgA->GetCenter(), dwgB->GetCenter() );
if( dwgA->GetCenter().x != dwgB->GetCenter().x )
return dwgA->GetCenter().x < dwgB->GetCenter().x;
if( dwgA->GetCenter().y != dwgB->GetCenter().y )
return dwgA->GetCenter().y < dwgB->GetCenter().y;
}
else if( dwgA->GetShape() == SHAPE_T::BEZIER )
{
TEST_PT( dwgA->GetBezierC1(), dwgB->GetBezierC1() );
TEST_PT( dwgA->GetBezierC2(), dwgB->GetBezierC2() );
if( dwgA->GetBezierC1().x != dwgB->GetBezierC1().x )
return dwgA->GetBezierC1().x < dwgB->GetBezierC1().x;
if( dwgA->GetBezierC1().y != dwgB->GetBezierC1().y )
return dwgA->GetBezierC1().y < dwgB->GetBezierC1().y;
if( dwgA->GetBezierC2().x != dwgB->GetBezierC2().x )
return dwgA->GetBezierC2().x < dwgB->GetBezierC2().x;
if( dwgA->GetBezierC2().y != dwgB->GetBezierC2().y )
return dwgA->GetBezierC2().y < dwgB->GetBezierC2().y;
}
else if( dwgA->GetShape() == SHAPE_T::POLY )
{
TEST( dwgA->GetPolyShape().TotalVertices(), dwgB->GetPolyShape().TotalVertices() );
if( dwgA->GetPolyShape().TotalVertices() != dwgB->GetPolyShape().TotalVertices() )
return dwgA->GetPolyShape().TotalVertices() < dwgB->GetPolyShape().TotalVertices();
for( int ii = 0; ii < dwgA->GetPolyShape().TotalVertices(); ++ii )
TEST_PT( dwgA->GetPolyShape().CVertex( ii ), dwgB->GetPolyShape().CVertex( ii ) );
{
if( dwgA->GetPolyShape().CVertex( ii ).x != dwgB->GetPolyShape().CVertex( ii ).x )
return dwgA->GetPolyShape().CVertex( ii ).x
< dwgB->GetPolyShape().CVertex( ii ).x;
if( dwgA->GetPolyShape().CVertex( ii ).y != dwgB->GetPolyShape().CVertex( ii ).y )
return dwgA->GetPolyShape().CVertex( ii ).y
< dwgB->GetPolyShape().CVertex( ii ).y;
}
}
TEST( dwgA->GetWidth(), dwgB->GetWidth() );
if( dwgA->GetWidth() != dwgB->GetWidth() )
return dwgA->GetWidth() < dwgB->GetWidth();
}
TEST( itemA->m_Uuid, itemB->m_Uuid ); // should be always the case for valid boards
if( itemA->m_Uuid != itemB->m_Uuid )
return itemA->m_Uuid < itemB->m_Uuid;
return itemA < itemB;
}
@ -3054,36 +3118,110 @@ bool FOOTPRINT::cmp_pads::operator()( const PAD* aFirst, const PAD* aSecond ) co
if( aFirst->GetNumber() != aSecond->GetNumber() )
return StrNumCmp( aFirst->GetNumber(), aSecond->GetNumber() ) < 0;
TEST_PT( aFirst->GetFPRelativePosition(), aSecond->GetFPRelativePosition() );
TEST_PT( aFirst->GetSize(), aSecond->GetSize() );
TEST( aFirst->GetShape(), aSecond->GetShape() );
TEST( aFirst->GetLayerSet().Seq(), aSecond->GetLayerSet().Seq() );
if( aFirst->GetFPRelativePosition().x != aSecond->GetFPRelativePosition().x )
return aFirst->GetFPRelativePosition().x < aSecond->GetFPRelativePosition().x;
if( aFirst->GetFPRelativePosition().y != aSecond->GetFPRelativePosition().y )
return aFirst->GetFPRelativePosition().y < aSecond->GetFPRelativePosition().y;
TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
if( aFirst->GetSize().x != aSecond->GetSize().x )
return aFirst->GetSize().x < aSecond->GetSize().x;
if( aFirst->GetSize().y != aSecond->GetSize().y )
return aFirst->GetSize().y < aSecond->GetSize().y;
if( aFirst->GetShape() != aSecond->GetShape() )
return aFirst->GetShape() < aSecond->GetShape();
if( aFirst->GetLayerSet().Seq() != aSecond->GetLayerSet().Seq() )
return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
if( aFirst->m_Uuid != aSecond->m_Uuid )
return aFirst->m_Uuid < aSecond->m_Uuid;
return aFirst < aSecond;
}
bool FOOTPRINT::cmp_padstack::operator()( const PAD* aFirst, const PAD* aSecond ) const
{
if( aFirst->GetSize().x != aSecond->GetSize().x )
return aFirst->GetSize().x < aSecond->GetSize().x;
if( aFirst->GetSize().y != aSecond->GetSize().y )
return aFirst->GetSize().y < aSecond->GetSize().y;
if( aFirst->GetShape() != aSecond->GetShape() )
return aFirst->GetShape() < aSecond->GetShape();
if( aFirst->GetLayerSet().Seq() != aSecond->GetLayerSet().Seq() )
return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
if( aFirst->GetDrillSizeX() != aSecond->GetDrillSizeX() )
return aFirst->GetDrillSizeX() < aSecond->GetDrillSizeX();
if( aFirst->GetDrillSizeY() != aSecond->GetDrillSizeY() )
return aFirst->GetDrillSizeY() < aSecond->GetDrillSizeY();
if( aFirst->GetDrillShape() != aSecond->GetDrillShape() )
return aFirst->GetDrillShape() < aSecond->GetDrillShape();
if( aFirst->GetAttribute() != aSecond->GetAttribute() )
return aFirst->GetAttribute() < aSecond->GetAttribute();
if( aFirst->GetOrientation() != aSecond->GetOrientation() )
return aFirst->GetOrientation() < aSecond->GetOrientation();
if( aFirst->GetSolderMaskExpansion() != aSecond->GetSolderMaskExpansion() )
return aFirst->GetSolderMaskExpansion() < aSecond->GetSolderMaskExpansion();
if( aFirst->GetSolderPasteMargin() != aSecond->GetSolderPasteMargin() )
return aFirst->GetSolderPasteMargin() < aSecond->GetSolderPasteMargin();
if( aFirst->GetLocalSolderMaskMargin() != aSecond->GetLocalSolderMaskMargin() )
return aFirst->GetLocalSolderMaskMargin() < aSecond->GetLocalSolderMaskMargin();
std::shared_ptr<SHAPE_POLY_SET> firstShape = aFirst->GetEffectivePolygon( ERROR_INSIDE );
std::shared_ptr<SHAPE_POLY_SET> secondShape = aSecond->GetEffectivePolygon( ERROR_INSIDE );
if( firstShape->VertexCount() != secondShape->VertexCount() )
return firstShape->VertexCount() < secondShape->VertexCount();
for( int ii = 0; ii < firstShape->VertexCount(); ++ii )
{
if( firstShape->CVertex( ii ).x != secondShape->CVertex( ii ).x )
return firstShape->CVertex( ii ).x < secondShape->CVertex( ii ).x;
if( firstShape->CVertex( ii ).y != secondShape->CVertex( ii ).y )
return firstShape->CVertex( ii ).y < secondShape->CVertex( ii ).y;
}
return false;
}
bool FOOTPRINT::cmp_zones::operator()( const ZONE* aFirst, const ZONE* aSecond ) const
{
TEST( aFirst->GetAssignedPriority(), aSecond->GetAssignedPriority() );
TEST( aFirst->GetLayerSet().Seq(), aSecond->GetLayerSet().Seq() );
if( aFirst->GetAssignedPriority() != aSecond->GetAssignedPriority() )
return aFirst->GetAssignedPriority() < aSecond->GetAssignedPriority();
TEST( aFirst->Outline()->TotalVertices(), aSecond->Outline()->TotalVertices() );
if( aFirst->GetLayerSet().Seq() != aSecond->GetLayerSet().Seq() )
return aFirst->GetLayerSet().Seq() < aSecond->GetLayerSet().Seq();
if( aFirst->Outline()->TotalVertices() != aSecond->Outline()->TotalVertices() )
return aFirst->Outline()->TotalVertices() < aSecond->Outline()->TotalVertices();
for( int ii = 0; ii < aFirst->Outline()->TotalVertices(); ++ii )
TEST_PT( aFirst->Outline()->CVertex( ii ), aSecond->Outline()->CVertex( ii ) );
{
if( aFirst->Outline()->CVertex( ii ).x != aSecond->Outline()->CVertex( ii ).x )
return aFirst->Outline()->CVertex( ii ).x < aSecond->Outline()->CVertex( ii ).x;
if( aFirst->Outline()->CVertex( ii ).y != aSecond->Outline()->CVertex( ii ).y )
return aFirst->Outline()->CVertex( ii ).y < aSecond->Outline()->CVertex( ii ).y;
}
TEST( aFirst->m_Uuid, aSecond->m_Uuid ); // should be always the case for valid boards
if( aFirst->m_Uuid != aSecond->m_Uuid )
return aFirst->m_Uuid < aSecond->m_Uuid;
return aFirst < aSecond;
}
#undef TEST
void FOOTPRINT::TransformPadsToPolySet( SHAPE_POLY_SET& aBuffer, PCB_LAYER_ID aLayer,
int aClearance, int aMaxError, ERROR_LOC aErrorLoc,
bool aSkipNPTHPadsWihNoCopper, bool aSkipPlatedPads,

View File

@ -934,6 +934,11 @@ public:
bool operator()( const PAD* aFirst, const PAD* aSecond ) const;
};
struct cmp_padstack
{
bool operator()( const PAD* aFirst, const PAD* aSecond ) const;
};
struct cmp_zones
{
bool operator()( const ZONE* aFirst, const ZONE* aSecond ) const;

View File

@ -43,6 +43,7 @@
#include <plugins/fabmaster/fabmaster_plugin.h>
#include <plugins/easyeda/pcb_easyeda_plugin.h>
#include <plugins/easyedapro/pcb_easyedapro_plugin.h>
#include <plugins/ipc2581/ipc2581_plugin.h>
#define FMT_UNIMPLEMENTED _( "Plugin \"%s\" does not implement the \"%s\" function." )
#define FMT_NOTFOUND _( "Plugin type \"%s\" is not found." )
@ -262,4 +263,9 @@ static IO_MGR::REGISTER_PLUGIN registerSolidworksPCBPlugin(
IO_MGR::SOLIDWORKS_PCB,
wxT( "Solidworks PCB" ),
[]() -> PLUGIN* { return new SOLIDWORKS_PCB_PLUGIN; } );
static IO_MGR::REGISTER_PLUGIN registerIPC2581Plugin(
IO_MGR::IPC2581,
wxT( "IPC-2581" ),
[]() -> PLUGIN* { return new IPC2581_PLUGIN; } );
// clang-format on

View File

@ -66,6 +66,7 @@ public:
GEDA_PCB, ///< Geda PCB file formats.
PCAD,
SOLIDWORKS_PCB,
IPC2581,
// add your type here.
// etc.
@ -373,11 +374,13 @@ public:
* tuning arguments that the plugin is known to support. The caller
* continues to own this object (plugin may not delete it) and plugins
* should expect it to be optionally NULL.
* @param aProgressReporter an optional progress reporter
*
* @throw IO_ERROR if there is a problem saving or exporting.
*/
virtual void SaveBoard( const wxString& aFileName, BOARD* aBoard,
const STRING_UTF8_MAP* aProperties = nullptr );
const STRING_UTF8_MAP* aProperties = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr );
/**
* Return a list of footprint names contained within the library at @a aLibraryPath.

View File

@ -330,7 +330,8 @@ BOARD_ITEM* CLIPBOARD_IO::Parse()
void CLIPBOARD_IO::SaveBoard( const wxString& aFileName, BOARD* aBoard,
const STRING_UTF8_MAP* aProperties )
const STRING_UTF8_MAP* aProperties,
PROGRESS_REPORTER* aProgressReporter )
{
init( aProperties );

View File

@ -48,7 +48,8 @@ public:
* Saves the entire board to the clipboard formatted using the PCB_PLUGIN formatting
*/
void SaveBoard( const wxString& aFileName, BOARD* aBoard,
const STRING_UTF8_MAP* aProperties = nullptr ) override;
const STRING_UTF8_MAP* aProperties = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr ) override;
/*
* Write all the settings of the BOARD* set by setBoard() and then adds all the

View File

@ -166,6 +166,10 @@ void PCB_EDIT_FRAME::doReCreateMenuBar()
submenuFabOutputs->Add( PCB_ACTIONS::generateGerbers );
submenuFabOutputs->Add( PCB_ACTIONS::generateDrillFiles );
if( ADVANCED_CFG::GetCfg().m_Enable2581 )
submenuFabOutputs->Add( PCB_ACTIONS::generateIPC2581File );
submenuFabOutputs->Add( PCB_ACTIONS::generatePosFile );
submenuFabOutputs->Add( PCB_ACTIONS::generateReportFile );
submenuFabOutputs->Add( PCB_ACTIONS::generateD356File );

View File

@ -333,6 +333,11 @@ public:
*/
void GenFootprintsReport( wxCommandEvent& event );
/**
* Create and IPC2581 output file
*/
void GenIPC2581File( wxCommandEvent& event );
/**
* Create an ASCII footprint report file giving some infos on footprints and board outlines.
*

View File

@ -1932,9 +1932,6 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
}
break;
case SHAPE_T::LAST:
break;
}
}
else

View File

@ -332,6 +332,18 @@ PCBNEW_SETTINGS::PCBNEW_SETTINGS()
m_params.emplace_back( new PARAM<int>( "gen_drill.zeros_format",
&m_GenDrill.zeros_format, 0, 0, 3 ) );
m_params.emplace_back( new PARAM<int>( "export_2581.units",
&m_Export2581.units, 0 ) );
m_params.emplace_back( new PARAM<int>( "export_2581.precision",
&m_Export2581.precision, 3 ) );
m_params.emplace_back( new PARAM<int>( "export_2581.version",
&m_Export2581.version, 1 ) );
m_params.emplace_back( new PARAM<bool>( "export_2581.compress",
&m_Export2581.compress, false ) );
m_params.emplace_back( new PARAM<bool>( "export_idf.auto_adjust",
&m_ExportIdf.auto_adjust, false ) );

View File

@ -188,6 +188,14 @@ public:
bool overwrite_file;
};
struct DIALOG_EXPORT_2581
{
int precision;
int units;
int version;
bool compress;
};
struct DIALOG_EXPORT_SVG
{
bool black_and_white;
@ -369,6 +377,8 @@ public:
DIALOG_EXPORT_STEP m_ExportStep;
DIALOG_EXPORT_2581 m_Export2581;
DIALOG_EXPORT_SVG m_ExportSvg;
DIALOG_EXPORT_VRML m_ExportVrml;

View File

@ -155,7 +155,8 @@ std::vector<FOOTPRINT*> PLUGIN::GetImportedCachedLibraryFootprints()
}
void PLUGIN::SaveBoard( const wxString& aFileName, BOARD* aBoard, const STRING_UTF8_MAP* aProperties )
void PLUGIN::SaveBoard( const wxString& aFileName, BOARD* aBoard,
const STRING_UTF8_MAP* aProperties, PROGRESS_REPORTER* aProgressReporter )
{
// not pure virtual so that plugins only have to implement subset of the PLUGIN interface.
NOT_IMPLEMENTED( __FUNCTION__ );

View File

@ -0,0 +1,13 @@
# Sources for the pcbnew PLUGIN called IPC2581_PLUGIN
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
set( IPC2581_SRCS
ipc2581_plugin.cpp
)
add_library( ipc2581 STATIC ${IPC2581_SRCS} )
target_link_libraries( ipc2581 pcbcommon )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,314 @@
/**
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef IPC2581_PLUGIN_H
#define IPC2581_PLUGIN_H
#include <eda_shape.h>
#include <io_mgr.h>
#include <layer_ids.h> // PCB_LAYER_ID
#include <plugins/common/plugin_common_layer_mapping.h>
#include <font/font.h>
#include <geometry/shape_segment.h>
#include <stroke_params.h>
#include <wx/xml/xml.h>
#include <memory>
class BOARD;
class BOARD_ITEM;
class EDA_TEXT;
class FOOTPRINT;
class PROGRESS_REPORTER;
class NETINFO_ITEM;
class PAD;
class PCB_SHAPE;
class PCB_VIA;
class PROGRESS_REPORTER;
class SHAPE_POLY_SET;
class SHAPE_SEGMENT;
class IPC2581_PLUGIN : public PLUGIN, public LAYER_REMAPPABLE_PLUGIN
{
public:
/**
* @brief IPC2581_PLUGIN
*
*/
IPC2581_PLUGIN(){}
~IPC2581_PLUGIN() override;
/**
* @brief IPC2581_PLUGIN
*/
const wxString PluginName() const override;
/**
*
*/
// BOARD* LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
// const STRING_UTF8_MAP* aProperties = nullptr, PROJECT* aProject = nullptr,
// PROGRESS_REPORTER* aProgressReporter = nullptr ) override;
void SaveBoard( const wxString& aFileName, BOARD* aBoard,
const STRING_UTF8_MAP* aProperties = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr ) override;
PLUGIN_FILE_DESC GetBoardFileDesc() const override
{
return PLUGIN_FILE_DESC( _HKI( "IPC-2581 Production File" ), { "xml" } );
}
std::vector<FOOTPRINT*> GetImportedCachedLibraryFootprints() override;
long long GetLibraryTimestamp( const wxString& aLibraryPath ) const override
{
return 0;
}
// Reading currently disabled
bool CanReadBoard( const wxString& aFileName ) const override
{
return false;
}
// Reading currently disabled
bool CanReadFootprint( const wxString& aFileName ) const override
{
return false;
}
// Reading currently disabled
bool CanReadFootprintLib( const wxString& aFileName ) const override
{
return false;
}
/**
* Return the automapped layers.
*
* @param aInputLayerDescriptionVector
* @return Auto-mapped layers
*/
// static std::map<wxString, PCB_LAYER_ID> DefaultLayerMappingCallback(
// const std::vector<INPUT_LAYER_DESC>& aInputLayerDescriptionVector );
/**
* Register a different handler to be called when mapping of IPC2581 to KiCad layers occurs.
*
* @param aLayerMappingHandler
*/
// void RegisterLayerMappingCallback( LAYER_MAPPING_HANDLER aLayerMappingHandler ) override
// {};
private:
/**
* Frees the memory allocated for the loaded footprints in #m_loaded_footprints.
*
*/
void clearLoadedFootprints();
/**
* Creates the XML header for IPC-2581
*
*/
wxXmlNode* generateXmlHeader();
/**
* Creates the Content section of the XML file. This holds the overview of
* the rest of the board data. Includes references to the step, bom, and layers
* as well as the content dictionaries
*/
wxXmlNode* generateContentSection();
/**
* Creates the logistical data header. This section defines the organization and person
* creating the file. Can be used for contact information and config management
*/
wxXmlNode* generateLogisticSection();
/**
* Creates the history section. This section defines the history of the file, the revision
* number, and the date of the revision as well as software used to create the file. Optionally,
* the data could include information about the git revision and tag
*/
wxXmlNode* generateHistorySection();
/**
* Creates the BOM section. This section defines the BOM data for the board. This includes
* the part number, manufacturer, and distributor information for each component on the board.
*/
wxXmlNode* generateBOMSection( wxXmlNode* aEcadNode );
/**
* Creates the ECAD section. This describes the layout, layers, and design as well as
* component placement and netlist information
*/
wxXmlNode* generateEcadSection();
/**
* Creates the Approved Vendor List section. If the user chooses, this will associate
* BOM items with vendor numbers and names.
*/
wxXmlNode* generateAvlSection();
void generateCadLayers( wxXmlNode* aCadLayerNode );
void generateDrillLayers( wxXmlNode* aCadLayerNode );
void generateStepSection( wxXmlNode* aCadNode );
void generateProfile( wxXmlNode* aStepNode );
void generateLogicalNets( wxXmlNode* aStepNode );
void generatePhyNetGroup( wxXmlNode* aStepNode );
void generateLayerFeatures( wxXmlNode* aStepNode );
void generateLayerSetDrill( wxXmlNode* aStepNode );
void generateLayerSetNet( wxXmlNode* aLayerNode, PCB_LAYER_ID aLayer, std::vector<BOARD_ITEM*>& aItems );
wxXmlNode* generateContentStackup( wxXmlNode* aContentNode );
void generateComponents( wxXmlNode* aStepNode );
void addCadHeader( wxXmlNode* aEcadNode );
wxXmlNode* addPackage( wxXmlNode* aStepNode, FOOTPRINT* aFootprint );
void addPad( wxXmlNode* aContentNode, const PAD* aPad, PCB_LAYER_ID aLayer );
void addVia( wxXmlNode* aContentNode, const PCB_VIA* aVia, PCB_LAYER_ID aLayer );
void addPadStack( wxXmlNode* aContentNode, const PAD* aPad );
void addPadStack( wxXmlNode* aContentNode, const PCB_VIA* aVia );
void addLocationNode( wxXmlNode* aContentNode, double aX, double aY );
void addLocationNode( wxXmlNode* aContentNode, const PAD& aPad, bool aRelative );
void addLocationNode( wxXmlNode* aContentNode, const PCB_SHAPE& aShape );
void addShape( wxXmlNode* aContentNode, const PCB_SHAPE& aShape );
void addShape( wxXmlNode* aContentNode, const PAD& aPad, PCB_LAYER_ID aLayer );
void addText( wxXmlNode* aContentNode, EDA_TEXT* aShape, const KIFONT::METRICS& aFontMetrics );
void addLineDesc( wxXmlNode* aNode, int aWidth, LINE_STYLE aDashType, bool aForce = false );
void addFillDesc( wxXmlNode* aNode, FILL_T aFillType, bool aForce = false );
bool addPolygonNode( wxXmlNode* aParentNode, const SHAPE_POLY_SET::POLYGON& aPolygon,
FILL_T aFillType = FILL_T::FILLED_SHAPE, int aWidth = 0,
LINE_STYLE aDashType = LINE_STYLE::SOLID );
bool addPolygonCutouts( wxXmlNode* aParentNode, const SHAPE_POLY_SET::POLYGON& aPolygon );
bool addOutlineNode( wxXmlNode* aParentNode, const SHAPE_POLY_SET& aPolySet, int aWidth = 0,
LINE_STYLE aDashType = LINE_STYLE::SOLID );
bool addContourNode( wxXmlNode* aParentNode, const SHAPE_POLY_SET& aPolySet, int aOutline = 0,
FILL_T aFillType = FILL_T::FILLED_SHAPE, int aWidth = 0,
LINE_STYLE aDashType = LINE_STYLE::SOLID );
size_t lineHash( int aWidth, LINE_STYLE aDashType );
size_t shapeHash( const PCB_SHAPE& aShape );
wxString genString( const wxString& aStr, const char* aPrefix = nullptr );
wxString floatVal( double aVal );
void addXY( wxXmlNode* aNode, const VECTOR2I& aVec, const char* aXName = nullptr,
const char* aYName = nullptr );
void addAttribute( wxXmlNode* aNode, const wxString& aName, const wxString& aValue );
wxXmlNode* insertNode( wxXmlNode* aParent, const wxString& aName );
wxXmlNode* appendNode( wxXmlNode* aParent, const wxString& aName );
void insertNode( wxXmlNode* aParent, wxXmlNode* aNode );
void insertNodeAfter( wxXmlNode* aPrev, wxXmlNode* aNode );
void addLayerAttributes( wxXmlNode* aNode, PCB_LAYER_ID aLayer );
private:
LAYER_MAPPING_HANDLER m_layerMappingHandler;
bool m_show_layer_mapping_warnings;
size_t m_total_bytes; //<! Total number of bytes to be written
wxString m_units_str; //<! Output string for units
double m_scale; //<! Scale factor from IU to IPC2581 units (mm, micron, in)
int m_sigfig; //<! Max number of digits past the decimal point
char m_version; //<! Currently, either 'B' or 'C' for the IPC2581 version
wxString m_OEMRef; //<! If set, field name containing the internal ID of parts
wxString m_mpn; //<! If set, field name containing the manufacturer part number
wxString m_mfg; //<! If set, field name containing the part manufacturer
wxString m_distpn; //<! If set, field name containing the distributor part number
wxString m_dist; //<! If set, field name containing the distributor name
// Node pointer to the main enterprise node to be used for adding
// enterprises later when forming the AVL
wxXmlNode* m_enterpriseNode;
BOARD* m_board;
std::vector<FOOTPRINT*> m_loaded_footprints;
const STRING_UTF8_MAP* m_props;
std::map<size_t, wxString> m_user_shape_dict; //<! Map between shape hash values and reference id string
wxXmlNode* m_shape_user_node; //<! Output XML node for reference shapes in UserDict
std::map<size_t, wxString> m_std_shape_dict; //<! Map between shape hash values and reference id string
wxXmlNode* m_shape_std_node; //<! Output XML node for reference shapes in StandardDict
std::map<size_t, wxString> m_line_dict; //<! Map between line hash values and reference id string
wxXmlNode* m_line_node; //<! Output XML node for reference lines in LineDict
std::map<size_t, wxString> m_padstack_dict; //<! Map between padstack hash values and reference id string (PADSTACK_##)
std::vector<wxXmlNode*> m_padstacks; //<! Holding vector for padstacks. These need to be inserted prior to the components
wxXmlNode* m_last_padstack; //<! Pointer to padstack list where we can insert the VIA padstacks once we process tracks
std::map<size_t, wxString> m_footprint_dict; //<! Map between the footprint hash values and reference id string (<fpid>_##)
std::map<FOOTPRINT*, wxString> m_OEMRef_dict; //<! Reverse map from the footprint pointer to the reference id string assigned for components
std::map<int, std::vector<std::pair<wxString, wxString>>> m_net_pin_dict; //<! Map from netcode to the component/pin pairs in the net
std::vector<SHAPE_SEGMENT> m_slot_holes; //<! Storage vector of slotted holes that need to be output as cutouts
std::map<PCB_LAYER_ID, wxString> m_layer_name_map; //<! Mapping layer name in 2581 to the internal layer id
std::map<std::pair<PCB_LAYER_ID, PCB_LAYER_ID>,std::vector<BOARD_ITEM*>> m_drill_layers; //<! Drill sets are output as layers (to/from pairs)
PROGRESS_REPORTER* m_progress_reporter;
std::set<wxUniChar> m_acceptable_chars; //<! IPC2581B and C have differing sets of allowed characters in names
wxXmlDocument* m_xml_doc;
wxXmlNode* m_xml_root;
};
#endif // IPC2581_PLUGIN_H

View File

@ -0,0 +1,823 @@
/**
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef IPC2581_TYPES_H
#define IPC2581_TYPES_H
#include <map>
#include <string>
enum class bomCategoryType
{
ELECTRICAL,
PROGRAMMABLE,
MECHANICAL,
MATERIAL,
DOCUMENT
};
enum class boardTechnologyType
{
RIGID,
RIGID_FLEX,
FLEX,
HDI,
EMBEDDED_COMPONENT,
OTHER
};
enum class butterflyShapeType
{
ROUND,
SQUARE
};
enum class cadPinType
{
THRU,
BLIND,
SURFACE
};
enum class certificationCategoryType
{
ASSEMBLYDRAWING,
ASSEMBLYFIXTUREGENERATION,
ASSEMBLYPANEL,
ASSEMBLYPREPTOOLS,
ASSEMBLYTESTFIXTUREGENERATION,
ASSEMBLYTESTGENERATION,
BOARDFABRICATION,
BOARDFIXTUREGENERATION,
BOARDPANEL,
BOARDTESTGENERATION,
COMPONENTPLACEMENT,
DETAILEDDRAWING,
FABRICATIONDRAWING,
GENERALASSEMBLY,
GLUEDOT,
MECHANICALHARDWARE,
MULTIBOARDPARTSLIST,
PHOTOTOOLS,
SCHEMATICDRAWINGS,
SINGLEBOARDPARTSLIST,
SOLDERSTENCILPASTE,
SPECSOURCECONTROLDRAWING,
EMBEDDEDCOMPONENT,
OTHER
};
enum class certificationStatusType
{
ALPHA,
BETA,
CERTIFIED,
SELFTEST
};
enum class complianceListType
{
ROHS,
CONFLICT_MINERALS,
WEEE,
REACH,
HALOGEN_FREE,
OTHER
};
enum class conductorListType
{
CONDUCTIVITY,
SURFACE_ROUGHNESS_UPFACING,
SURFACE_ROUGHNESS_DOWNFACING,
SURFACE_ROUGHNESS_TREATED,
ETCH_FACTOR,
FINISHED_HEIGHT,
OTHER
};
enum class colorListType
{
BLACK,
WHITE,
RED,
GREEN,
YELLOW,
BLUE,
BROWN,
ORANGE,
PINK,
PURPLE,
GRAY,
OTHER
};
enum class contextType
{
BOARD,
BOARDPANEL,
ASSEMBLY,
ASSEMBLYPALLET,
DOCUMENTATION,
TOOLING,
COUPON,
MISCELLANEOUS
};
enum class dfxCategoryType
{
COMPONENT,
BOARDFAB,
ASSEMBLY,
TESTING,
DATAQUALITY
};
enum class dielectricListType
{
DIELECTRIC_CONSTANT,
LOSS_TANGENT,
GLASS_TYPE,
GLASS_STYLE,
RESIN_CONTENT,
PROCESSABILITY_TEMP,
OTHER
};
enum class donutShapeType
{
ROUND,
SQUARE,
HEXAGON,
OCTAGON
};
enum class toolListType
{
CARBIDE,
ROUTER,
LASER,
FLATNOSE,
EXTENSION,
V_CUTTER
};
enum class toolPropertyListType
{
DRILL_SIZE,
FINISHED_SIZE,
BIT_ANGLE,
OTHER
};
enum class enterpriseCodeType
{
DUNNS,
CAGE
};
enum class exposureType
{
EXPOSED,
COVERED_PRIMARY,
COVERED_SECONDARY,
COVERED
};
enum class floorLifeType
{
UNLIMITED,
_1_YEAR,
_4_WEEKS,
_168_HOURS,
_72_HOURS,
_48_HOURS,
_24_HOURS,
BAKE
};
enum class geometryUsageType
{
THIEVING,
THERMAL_RELIEF,
NONE
};
enum class generalListType
{
ELECTRICAL,
THERMAL,
MATERIAL,
INSTRUCTION,
STANDARD,
CONFIGURATION,
OTHER
};
enum class impedanceListType
{
IMPEDANCE,
LINEWIDTH,
SPACING,
REF_PLANE_LAYER_ID,
COPLANAR_GROUND_SPACING,
OTHER
};
enum class isoCodeType
{
AD,
AE,
AF,
AG,
AI,
AL,
AM,
AN,
AO,
AQ,
AR,
AS,
AT,
AU,
AW,
AZ,
BA,
BB,
BD,
BE,
BF,
BG,
BH,
BI,
BJ,
BM,
BN,
BO,
BR,
BS,
BT,
BV,
BW,
BY,
BZ,
CA,
CC,
CF,
CG,
CH,
CI,
CK,
CL,
CM,
CN,
CO,
CR,
CU,
CV,
CX,
CY,
CZ,
DE,
DJ,
DK,
DM,
DO,
DZ,
EC,
EE,
EG,
EH,
ER,
ES,
ET,
FI,
FJ,
FK,
FM,
FO,
FR,
FX,
GA,
GB,
GD,
GE,
GF,
GH,
GI,
GL,
GM,
GN,
GP,
GQ,
GR,
GS,
GT,
GU,
GW,
GY,
HK,
HM,
HN,
HR,
HT,
HU,
ID,
IE,
IL,
IN,
IO,
IQ,
IR,
IS,
IT,
JM,
JO,
JP,
KE,
KG,
KH,
KI,
KM,
KN,
KP,
KR,
KW,
KY,
KZ,
LA,
LB,
LC,
LI,
LK,
LR,
LS,
LT,
LU,
LV,
LY,
MA,
MC,
MD,
MG,
MH,
MK,
ML,
MM,
MN,
MO,
MP,
MQ,
MR,
MS,
MT,
MU,
MV,
MW,
MX,
MY,
MZ,
NA,
NC,
NE,
NF,
NG,
NI,
NL,
NO,
NP,
NR,
NU,
NZ,
OM,
PA,
PE,
PF,
PG,
PH,
PK,
PL,
PM,
PN,
PR,
PT,
PW,
PY,
QA,
RE,
RO,
RU,
RW,
SA,
SB,
SC,
SD,
SE,
SG,
SH,
SI,
SJ,
SK,
SL,
SM,
SN,
SO,
SR,
ST,
SV,
SY,
SZ,
TC,
TD,
TF,
TG,
TH,
TJ,
TK,
TM,
TN,
TO,
TP,
TR,
TT,
TV,
TW,
TZ,
UA,
UG,
UM,
US,
UY,
UZ,
VA,
VC,
VE,
VG,
VI,
VN,
VU,
WF,
WS,
YE,
YT,
YU,
ZA,
ZM,
ZR,
ZW
};
enum class lineEndType
{
NONE,
ROUND,
SQUARE
};
enum class fillPropertyType
{
HOLLOW,
HATCH,
MESH,
FILL,
VOID
};
enum class linePropertyType
{
SOLID,
DOTTED,
DASHED,
CENTER,
PHANTOM,
ERASE
};
enum class markingUsageType
{
REFDES,
PARTNAME,
TARGET,
POLARITY_MARKING,
ATTRIBUTE_GRAPHICS,
PIN_ONE,
NONE
};
enum class mountType
{
SMT,
THMT,
OTHER
};
enum class netClassType
{
CLK,
FIXED,
GROUND,
SIGNAL,
POWER,
UNUSED
};
enum class netPointType
{
END,
MIDDLE
};
enum class packageTypeType
{
AXIAL_LEADED,
BARE_DIE,
CERAMIC_BGA,
CERAMIC_DIP,
CERAMIC_FLATPACK,
CERAMIC_QUAD_FLATPACK,
CERAMIC_SIP,
CHIP,
CHIP_SCALE,
CHOKE_SWITCH_SM,
COIL,
CONNECTOR_SM,
CONNECTOR_TH,
EMBEDDED,
FLIPCHIP,
HERMETIC_HYBRED,
LEADLESS_CERAMIC_CHIP_CARRIER,
MCM,
MELF,
FINEPITCH_BGA,
MOLDED,
NETWORK,
PGA,
PLASTIC_BGA,
PLASTIC_CHIP_CARRIER,
PLASTIC_DIP,
PLASTIC_SIP,
POWER_TRANSISTOR,
RADIAL_LEADED,
RECTANGULAR_QUAD_FLATPACK,
RELAY_SM,
RELAY_TH,
SOD123,
SOIC,
SOJ,
SOPIC,
SOT143,
SOT23,
SOT52,
SOT89,
SQUARE_QUAD_FLATPACK,
SSOIC,
SWITCH_TH,
TANTALUM,
TO_TYPE,
TRANSFORMER,
TRIMPOT_SM,
TRIMPOT_TH,
OTHER
};
enum class padUsageType
{
TERMINATION,
VIA,
PLANE,
MASK,
TOOLING_HOLE,
THIEVING,
THERMAL_RELIEF,
FIDUCIAL,
NONE
};
enum class padUseType
{
REGULAR,
ANTIPAD,
THERMAL,
OTHER
};
enum class pinElectricalType
{
ELECTRICAL,
MECHANICAL,
UNDEFINED
};
enum class pinMountType
{
SURFACE_MOUNT_PIN,
SURFACE_MOUNT_PAD,
THROUGH_HOLE_PIN,
THROUGH_HOLE_HOLE,
PRESSFIT,
NONBOARD,
HOLE,
UNDEFINED
};
enum class pinOneOrientationType
{
LOWER_LEFT,
LEFT,
LEFT_CENTER,
UPPER_LEFT,
UPPER_CENTER,
UPPER_RIGHT,
RIGHT,
RIGHT_CENTER,
LOWER_RIGHT,
LOWER_CENTER,
CENTER,
OTHER
};
enum class polarityType
{
POSITIVE,
NEGATIVE
};
enum class propertyUnitType
{
MM,
INCH,
MICRON,
OHMS,
MHO_CM,
SIEMENS_M,
CELCIUS,
FARANHEIT,
PERCENT,
Hz,
DEGREES,
RMAX,
RZ,
RMS,
SECTION,
CLASS,
ITEM,
GAUGE,
OTHER
};
enum class roleFunctionType
{
SENDER,
OWNER,
RECEIVER,
DESIGNER,
ENGINEER,
BUYER,
CUSTOMERSERVICE,
DELIVERTO,
BILLTO,
OTHER
};
enum class platingStatusType
{
PLATED,
NONPLATED,
VIA
};
enum class standardPrimitive
{
BUTTERFLY,
CIRCLE,
CONTOUR,
DIAMOND,
DONUT,
ELLIPSE,
HEXAGON,
MOIRE,
OCTAGON,
OVAL,
RECTCENTER,
RECTCHAM,
RECTCORNER,
RECTROUND,
THERMAL,
TRIANGLE
};
enum class structureListType
{
STRIPLINE,
PLANE_LESS_STRIPLINE,
MICROSTRIP_EMBEDDED,
MICROSTRIP_NO_MASK,
MICROSTRIP_MASK_COVERED,
MICROSTRIP_DUAL_MASKED_COVERED,
COPLANAR_WAVEGUIDE_STRIPLINE,
COPLANAR_WAVEGUIDE_EMBEDDED,
COPLANAR_WAVEGUIDE_NO_MASK,
COPLANAR_WAVEGUIDE_MASK_COVERED,
COPLANAR_WAVEGUIDE_DUAL_MASKED_COVERED,
OTHER
};
enum class technologyListType
{
RIGID,
RIGID_FLEX,
FLEX,
HDI,
EMBEDDED_COMPONENT,
OTHER
};
enum class temperatureListType
{
THERMAL_DELAMINATION,
EXPANSION_Z_AXIS,
EXPANSION_X_Y_AXIS,
OTHER
};
enum class thermalShapeType
{
ROUND,
SQUARE,
HEXAGON,
OCTAGON
};
enum class thievingListType
{
KEEP_IN,
KEEP_OUT
};
enum class transmissionListType
{
SINGLE_ENDED,
EDGE_COUPLED,
BROADSIDE_COUPLED,
OTHER
};
enum class unitModeType
{
DISTANCE,
AREA,
RESISTANCE,
CAPACITANCE,
IMPEDANCE,
PERCENTAGE,
SIZE,
NONE
};
enum class unitsType
{
MILLIMETER,
MICRON,
INCH
};
enum class vCutListType
{
ANGLE,
THICKNESS_REMAINING,
OFFSET,
OTHER
};
enum class edgeChamferListType
{
ANGLE,
WIDTH,
SIDE
};
enum class whereMeasuredType
{
LAMINATE,
METAL,
MASK,
OTHER
};
#endif // IPC2581_TYPES_H

View File

@ -292,7 +292,8 @@ bool PCB_PLUGIN::CanReadBoard( const wxString& aFileName ) const
void PCB_PLUGIN::SaveBoard( const wxString& aFileName, BOARD* aBoard,
const STRING_UTF8_MAP* aProperties )
const STRING_UTF8_MAP* aProperties,
PROGRESS_REPORTER* aProgressReporter )
{
LOCALE_IO toggle; // toggles on, then off, the C locale.

View File

@ -305,7 +305,8 @@ public:
bool CanReadBoard( const wxString& aFileName ) const override;
void SaveBoard( const wxString& aFileName, BOARD* aBoard,
const STRING_UTF8_MAP* aProperties = nullptr ) override;
const STRING_UTF8_MAP* aProperties = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr ) override;
BOARD* LoadBoard( const wxString& aFileName, BOARD* aAppendToMe,
const STRING_UTF8_MAP* aProperties = nullptr, PROJECT* aProject = nullptr,

View File

@ -503,6 +503,8 @@ int BOARD_EDITOR_CONTROL::GenerateFabFiles( const TOOL_EVENT& aEvent )
m_frame->GenD356File( dummy );
else if( aEvent.IsAction( &PCB_ACTIONS::generateBOM ) )
m_frame->RecreateBOMFileFromBoard( dummy );
else if( aEvent.IsAction( &PCB_ACTIONS::generateIPC2581File ) )
m_frame->GenIPC2581File( dummy );
else
wxFAIL_MSG( wxT( "GenerateFabFiles(): unexpected request" ) );
@ -1655,6 +1657,7 @@ void BOARD_EDITOR_CONTROL::setTransitions()
Go( &BOARD_EDITOR_CONTROL::GenerateFabFiles, PCB_ACTIONS::generateReportFile.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::GenerateFabFiles, PCB_ACTIONS::generateD356File.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::GenerateFabFiles, PCB_ACTIONS::generateBOM.MakeEvent() );
Go( &BOARD_EDITOR_CONTROL::GenerateFabFiles, PCB_ACTIONS::generateIPC2581File.MakeEvent() );
// Track & via size control
Go( &BOARD_EDITOR_CONTROL::TrackWidthInc, PCB_ACTIONS::trackWidthInc.MakeEvent() );

View File

@ -1056,6 +1056,13 @@ TOOL_ACTION PCB_ACTIONS::generateReportFile( TOOL_ACTION_ARGS()
.Tooltip( _( "Create report of all footprints from current board" ) )
.Icon( BITMAPS::post_rpt ) );
TOOL_ACTION PCB_ACTIONS::generateIPC2581File( TOOL_ACTION_ARGS()
.Name( "pcbnew.EditorControl.generateIPC2581File" )
.Scope( AS_GLOBAL )
.FriendlyName( _( "IPC-2581 File (.xml)..." ) )
.Tooltip( _( "Generate an IPC-2581 file" ) )
.Icon( BITMAPS::post_xml ) );
TOOL_ACTION PCB_ACTIONS::generateD356File( TOOL_ACTION_ARGS()
.Name( "pcbnew.EditorControl.generateD356File" )
.Scope( AS_GLOBAL )

View File

@ -424,6 +424,7 @@ public:
static TOOL_ACTION generateDrillFiles;
static TOOL_ACTION generatePosFile;
static TOOL_ACTION generateReportFile;
static TOOL_ACTION generateIPC2581File;
static TOOL_ACTION generateD356File;
static TOOL_ACTION generateBOM;

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,7 @@ set( COMMON_SRCS
../../../pcbnew/drc/drc_test_provider_diff_pair_coupling.cpp
../../../pcbnew/drc/drc_engine.cpp
../../../pcbnew/drc/drc_item.cpp
../../../pcbnew/board_stackup_manager/stackup_predefined_prms.cpp
pns_log_file.cpp
pns_log_player.cpp
pns_test_debug_decorator.cpp
@ -65,7 +66,7 @@ add_executable( pns_debug_tool
../../qa_utils/test_app_main.cpp
../../qa_utils/utility_program.cpp
../../qa_utils/mocks.cpp
playground.cpp
pns_debug_tool_main.cpp
)

View File

@ -429,6 +429,7 @@ set( BMAPS_MID
post_gencad
post_gerber
post_rpt
post_xml
preference
print_button
project

Binary file not shown.

After

Width:  |  Height:  |  Size: 562 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 745 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="Слой_1"
data-name="Слой 1"
viewBox="0 0 24 24"
version="1.1"
sodipodi:docname="post_xml.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2109"
id="namedview159354"
showgrid="true"
inkscape:zoom="30.291667"
inkscape:cx="21.392022"
inkscape:cy="16.225584"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="Слой_1"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid6877"
empspacing="2"
spacingx="0.5"
spacingy="0.5" />
</sodipodi:namedview>
<metadata
id="metadata43">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>post_xml</dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs159331">
<style
id="style159329">.cls-1{fill:#b9b9b9;}.cls-2{fill:#1a81c4;}.cls-3{fill:#fff;}.cls-4{fill:#bf2641;}.cls-5{fill:none;stroke:#f5f5f5;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px;}</style>
</defs>
<title
id="title159333">post_xml</title>
<rect
class="cls-1"
x="3.0489998"
y="0"
width="17.937201"
height="17.983299"
rx="2.9934001"
id="rect159335"
style="fill:#8f8f8f;fill-opacity:1" />
<rect
class="cls-2"
x="0.00010001659"
y="2.9995"
width="18.7099"
height="9.2299004"
id="rect159337"
style="fill:#42b8eb;fill-opacity:1" />
<g
aria-label="xml"
id="text5854"
style="font-size:8.52777px;line-height:1.25;font-family:'Tiresias LPfont';-inkscape-font-specification:'Tiresias LPfont';stroke-width:0.700254">
<path
d="M 3.8969283,7.587901 2.6647828,5.3280419 H 3.7175654 L 4.4974043,6.880096 5.2850417,5.3280419 H 6.3300259 L 5.0900819,7.5964287 6.3846146,9.958621 H 5.3396304 L 4.4896059,8.3042336 3.6473799,9.958621 H 2.6023957 Z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff;stroke-width:0.669638"
id="path6460" />
<path
d="m 10.980765,5.2427642 c 0.391193,0 0.545706,0.1364443 0.743658,0.409333 0.197954,0.2672034 0.29693,0.6907493 0.29693,1.2706377 V 9.958621 H 11.037525 V 7.1529847 c 0,-0.6992771 -0.07181,-0.9380351 -0.448863,-0.9380351 -0.230177,0 -0.352273,0.081193 -0.455934,0.2643412 C 10.019612,6.7237536 9.998069,7.0790774 9.998069,7.5452621 V 9.958621 H 9.0609388 V 7.1444569 C 9.0609388,6.450865 8.8838823,6.1689327 8.5070321,6.1565914 8.277701,6.1490811 8.1739136,6.3182798 8.1128246,6.481079 8.0091349,6.7539677 7.9864691,7.1842532 7.9864691,7.6902342 V 9.958621 H 6.9792978 V 5.3280419 h 0.6645567 l 0.03725,0.6139994 h 0.049488 C 7.8295695,5.7032638 8.0468304,5.5270232 8.2306439,5.4133196 8.4144575,5.299616 8.6147672,5.2427642 8.8315729,5.2427642 c 0.5184395,0 0.8624963,0.235935 1.0321705,0.7078049 h 0.063628 C 10.035774,5.7117916 10.181883,5.535551 10.365696,5.4218474 10.554223,5.3024586 10.759246,5.2427642 10.980765,5.2427642 Z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff;stroke-width:0.637588"
id="path6462"
sodipodi:nodetypes="scsccsscsccsscsccccccsscccs" />
<path
d="M 14.018376,9.958621 H 12.986515 V 3.4775158 h 1.031861 z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff"
id="path6464" />
</g>
<path
class="cls-3"
d="M 2.07,9.9365 H 0.9965 V 8.9 H 2.07 Z"
id="path159339" />
<ellipse
class="cls-4"
cx="17.0075"
cy="16.996099"
rx="6.9924002"
ry="7.0039001"
id="ellipse159347"
style="fill:#f2647e;fill-opacity:1" />
<line
class="cls-5"
x1="17.1112"
y1="13.6254"
x2="17.1112"
y2="20.629299"
id="line159349" />
<polyline
class="cls-5"
points="15.362 17.16 18.111 14.406 20.861 17.16"
id="polyline159351"
transform="translate(-1,-1)" />
</svg>

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@ -1,40 +1,137 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
<svg
id="Слой_1"
data-name="Слой 1"
viewBox="0 0 24 24"
version="1.1"
sodipodi:docname="post_rpt.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="Слой_1" data-name="Слой 1" viewBox="0 0 24 24" version="1.1" sodipodi:docname="post_rpt.svg" inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1488" inkscape:window-height="975" id="namedview159354" showgrid="false" inkscape:zoom="30.291667" inkscape:cx="3.0701513" inkscape:cy="12" inkscape:window-x="0" inkscape:window-y="37" inkscape:window-maximized="0" inkscape:current-layer="Слой_1" />
<metadata id="metadata43">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<cc:license rdf:resource="http://creativecommons.org/licenses/by/4.0/" />
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
<defs id="defs159331">
<style id="style159329">.cls-1{fill:#b9b9b9;}.cls-2{fill:#1a81c4;}.cls-3{fill:#fff;}.cls-4{fill:#bf2641;}.cls-5{fill:none;stroke:#f5f5f5;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px;}</style>
</defs>
<title id="title159333">post_rpt</title>
<rect class="cls-1" x="3.0489998" y="0" width="17.937201" height="17.983299" rx="2.9934001" id="rect159335" />
<rect class="cls-2" x="0.00010001659" y="2.9995" width="18.7099" height="9.2299004" id="rect159337" />
<path class="cls-3" d="M 2.07,9.9365 H 0.9965 V 8.9 H 2.07 Z" id="path159339" />
<path class="cls-3" d="M 5.8119,6.1 5.351,6.082 A 0.96,0.96 0 0 0 4.8246,6.2158 0.8793,0.8793 0 0 0 4.4994,6.5928 V 9.9365 H 3.4213 V 5.126 H 4.4057 L 4.4769,5.8242 A 1.5456,1.5456 0 0 1 4.9447,5.2461 1.0838,1.0838 0 0 1 5.6029,5.0371 0.9823,0.9823 0 0 1 5.7855,5.0527 1.4452,1.4452 0 0 1 5.9398,5.0908 Z" id="path159341" />
<path class="cls-3" d="M 10.77,7.6914 A 2.7166,2.7166 0 0 1 10.2778,9.3848 1.625,1.625 0 0 1 8.9078,10.0303 1.68,1.68 0 0 1 8.1851,9.8828 1.4832,1.4832 0 0 1 7.6441,9.4521 v 2.334 H 6.5658 V 5.126 H 7.475 L 7.5814,5.7305 A 1.6071,1.6071 0 0 1 8.1381,5.2148 1.5582,1.5582 0 0 1 8.8939,5.0371 1.5937,1.5937 0 0 1 10.2758,5.7422 3.1693,3.1693 0 0 1 10.77,7.5977 Z M 9.6968,7.5957 A 2.3439,2.3439 0 0 0 9.4194,6.3906 0.9,0.9 0 0 0 8.5923,5.9219 1.0651,1.0651 0 0 0 8.021,6.0664 1.0532,1.0532 0 0 0 7.644,6.4678 V 8.6387 A 0.9969,0.9969 0 0 0 8.021,9.0273 1.1373,1.1373 0 0 0 8.601,9.1631 0.9249,0.9249 0 0 0 9.4242,8.7568 1.8858,1.8858 0 0 0 9.6967,7.6885 Z" id="path159343" />
<path class="cls-3" d="m 13.0492,3.957 v 1.169 h 0.86 v 0.8008 h -0.86 V 8.585 a 0.582,0.582 0 0 0 0.1279,0.4248 0.4692,0.4692 0 0 0 0.3418,0.1269 1.0134,1.0134 0 0 0 0.1729,-0.0156 0.9933,0.9933 0 0 0 0.1592,-0.043 l 0.1162,0.792 A 1.2639,1.2639 0 0 1 13.639,9.9873 1.8184,1.8184 0 0 1 13.2435,10.0303 1.2309,1.2309 0 0 1 12.3129,9.6803 1.53,1.53 0 0 1 11.976,8.585 V 5.9268 H 11.2435 V 5.126 H 11.976 V 3.957 Z" id="path159345" />
<ellipse class="cls-4" cx="17.0075" cy="16.996099" rx="6.9924002" ry="7.0039001" id="ellipse159347" />
<line class="cls-5" x1="17.1112" y1="13.6254" x2="17.1112" y2="20.629299" id="line159349" />
<polyline class="cls-5" points="15.362 17.16 18.111 14.406 20.861 17.16" id="polyline159351" transform="translate(-1,-1)" />
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2109"
id="namedview159354"
showgrid="true"
inkscape:zoom="85.677773"
inkscape:cx="12.021788"
inkscape:cy="8.7829081"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="Слой_1"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid6877"
empspacing="2"
spacingx="0.5"
spacingy="0.5" />
</sodipodi:namedview>
<metadata
id="metadata43">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>post_xml</dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs159331">
<style
id="style159329">.cls-1{fill:#b9b9b9;}.cls-2{fill:#1a81c4;}.cls-3{fill:#fff;}.cls-4{fill:#bf2641;}.cls-5{fill:none;stroke:#f5f5f5;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px;}</style>
</defs>
<title
id="title159333">post_xml</title>
<rect
class="cls-1"
x="3.0489998"
y="0"
width="17.937201"
height="17.983299"
rx="2.9934001"
id="rect159335" />
<rect
class="cls-2"
x="0.00010001659"
y="2.9995"
width="18.7099"
height="9.2299004"
id="rect159337" />
<g
aria-label="xml"
id="text5854"
style="font-size:8.52777px;line-height:1.25;font-family:'Tiresias LPfont';-inkscape-font-specification:'Tiresias LPfont';stroke-width:0.700254">
<path
d="M 4.0180055,7.587901 2.6706178,5.3280419 h 1.151249 L 4.6746438,6.880096 5.5359486,5.3280419 H 6.6786698 L 5.3227543,7.5964287 6.7383641,9.958621 H 5.595643 L 4.666116,8.3042336 3.7451169,9.958621 H 2.6023957 Z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff"
id="path6460" />
<path
d="m 12.27288,5.2427642 q 0.707805,0 1.065971,0.409333 0.358166,0.4008051 0.358166,1.2706377 V 9.958621 h -1.03186 V 7.1529847 q 0,-1.0489157 -0.682221,-1.0489157 -0.486083,0 -0.69075,0.3752218 Q 11.08752,6.845985 11.08752,7.5452621 V 9.958621 H 10.055659 V 7.1444569 q 0,-1.0403879 -0.6822211,-1.0403879 -0.520194,0 -0.7078049,0.4178607 -0.187611,0.409333 -0.187611,1.1683045 V 9.958621 H 7.4461618 V 5.3280419 h 0.8016104 l 0.1364443,0.6139994 h 0.059694 Q 8.6229941,5.583875 8.9555771,5.4133196 9.2881602,5.2427642 9.6804376,5.2427642 q 0.9380544,0 1.2450544,0.7078049 h 0.07675 q 0.196139,-0.3581663 0.528722,-0.5287217 0.34111,-0.1790832 0.741916,-0.1790832 z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff"
id="path6462" />
<path
d="M 15.948344,9.958621 H 14.916483 V 3.4775158 h 1.031861 z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff"
id="path6464" />
</g>
<path
class="cls-3"
d="M 2.07,9.9365 H 0.9965 V 8.9 H 2.07 Z"
id="path159339" />
<ellipse
class="cls-4"
cx="17.0075"
cy="16.996099"
rx="6.9924002"
ry="7.0039001"
id="ellipse159347" />
<line
class="cls-5"
x1="17.1112"
y1="13.6254"
x2="17.1112"
y2="20.629299"
id="line159349" />
<polyline
class="cls-5"
points="15.362 17.16 18.111 14.406 20.861 17.16"
id="polyline159351"
transform="translate(-1,-1)" />
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="Слой_1"
data-name="Слой 1"
viewBox="0 0 24 24"
version="1.1"
sodipodi:docname="post_xml.svg"
inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="3840"
inkscape:window-height="2109"
id="namedview159354"
showgrid="true"
inkscape:zoom="30.291667"
inkscape:cx="21.392022"
inkscape:cy="16.225584"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="Слой_1"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid6877"
empspacing="2"
spacingx="0.5"
spacingy="0.5" />
</sodipodi:namedview>
<metadata
id="metadata43">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>post_xml</dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs159331">
<style
id="style159329">.cls-1{fill:#b9b9b9;}.cls-2{fill:#1a81c4;}.cls-3{fill:#fff;}.cls-4{fill:#bf2641;}.cls-5{fill:none;stroke:#f5f5f5;stroke-linecap:round;stroke-linejoin:round;stroke-width:2px;}</style>
</defs>
<title
id="title159333">post_xml</title>
<rect
class="cls-1"
x="3.0489998"
y="0"
width="17.937201"
height="17.983299"
rx="2.9934001"
id="rect159335" />
<rect
class="cls-2"
x="0.00010001659"
y="2.9995"
width="18.7099"
height="9.2299004"
id="rect159337" />
<g
aria-label="xml"
id="text5854"
style="font-size:8.52777px;line-height:1.25;font-family:'Tiresias LPfont';-inkscape-font-specification:'Tiresias LPfont';stroke-width:0.700254">
<path
d="M 3.8969283,7.587901 2.6647828,5.3280419 H 3.7175654 L 4.4974043,6.880096 5.2850417,5.3280419 H 6.3300259 L 5.0900819,7.5964287 6.3846146,9.958621 H 5.3396304 L 4.4896059,8.3042336 3.6473799,9.958621 H 2.6023957 Z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff;stroke-width:0.669638"
id="path6460" />
<path
d="m 10.980765,5.2427642 c 0.391193,0 0.545706,0.1364443 0.743658,0.409333 0.197954,0.2672034 0.29693,0.6907493 0.29693,1.2706377 V 9.958621 H 11.037525 V 7.1529847 c 0,-0.6992771 -0.07181,-0.9380351 -0.448863,-0.9380351 -0.230177,0 -0.352273,0.081193 -0.455934,0.2643412 C 10.019612,6.7237536 9.998069,7.0790774 9.998069,7.5452621 V 9.958621 H 9.0609388 V 7.1444569 C 9.0609388,6.450865 8.8838823,6.1689327 8.5070321,6.1565914 8.277701,6.1490811 8.1739136,6.3182798 8.1128246,6.481079 8.0091349,6.7539677 7.9864691,7.1842532 7.9864691,7.6902342 V 9.958621 H 6.9792978 V 5.3280419 h 0.6645567 l 0.03725,0.6139994 h 0.049488 C 7.8295695,5.7032638 8.0468304,5.5270232 8.2306439,5.4133196 8.4144575,5.299616 8.6147672,5.2427642 8.8315729,5.2427642 c 0.5184395,0 0.8624963,0.235935 1.0321705,0.7078049 h 0.063628 C 10.035774,5.7117916 10.181883,5.535551 10.365696,5.4218474 10.554223,5.3024586 10.759246,5.2427642 10.980765,5.2427642 Z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff;stroke-width:0.637588"
id="path6462"
sodipodi:nodetypes="scsccsscsccsscsccccccsscccs" />
<path
d="M 14.018376,9.958621 H 12.986515 V 3.4775158 h 1.031861 z"
style="font-weight:600;font-stretch:semi-condensed;font-family:'Noto Sans';-inkscape-font-specification:'Noto Sans Semi-Bold Semi-Condensed';fill:#ffffff"
id="path6464" />
</g>
<path
class="cls-3"
d="M 2.07,9.9365 H 0.9965 V 8.9 H 2.07 Z"
id="path159339" />
<ellipse
class="cls-4"
cx="17.0075"
cy="16.996099"
rx="6.9924002"
ry="7.0039001"
id="ellipse159347" />
<line
class="cls-5"
x1="17.1112"
y1="13.6254"
x2="17.1112"
y2="20.629299"
id="line159349" />
<polyline
class="cls-5"
points="15.362 17.16 18.111 14.406 20.861 17.16"
id="polyline159351"
transform="translate(-1,-1)" />
</svg>

After

Width:  |  Height:  |  Size: 5.6 KiB