7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2024-11-25 09:35:01 +00:00
kicad/pcbnew/pcb_io/odbpp/odb_util.h
Eric 1506beecbc Implement ODB++ export
ADDED: Add support in Pcbnew for exporting ODB++ files under Fabrication
       Outputs, base on ODB++Design Format Specification (Release v8.1
       Update 3 February 2021).

Note: There is still a lot of work to do if we will make the feature as
      complete as the ODB++ spec.  However, the current functionality's
      completeness is already sufficient to cover general production
      scenarios. I have compared the output results with Gerber files by
      DFM tool and the accuracy at the graphic level should be able to
      cover most usage scenarios.  Additionally, I am very grateful to
      the great open-source project Horizon EDA for giving me a lot of
      inspiration in terms of ideas.

The feature can be enabled by adding "EnableODB=1" to the kicad_advanced
configuration file.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/2019
2024-09-14 15:34:51 +00:00

356 lines
8.5 KiB
C++

#ifndef _ODB_UTIL_H_
#define _ODB_UTIL_H_
#include <map>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <wx/string.h>
#include "pcb_shape.h"
#include <wx/filename.h>
enum class ODB_POLARITY
{
POSITIVE,
NEGATIVE
};
enum class ODB_CONTEXT
{
BOARD,
MISC
};
enum class ODB_DIELECTRIC_TYPE
{
NONE,
PREPREG,
CORE
};
enum class ODB_TYPE
{
UNDEFINED,
SIGNAL,
POWER_GROUND,
DIELECTRIC,
MIXED,
SOLDER_MASK,
SOLDER_PASTE,
SILK_SCREEN,
DRILL,
ROUT,
DOCUMENT,
COMPONENT,
MASK,
CONDUCTIVE_PASTE,
};
enum class ODB_SUBTYPE
{
COVERLAY,
COVERCOAT,
STIFFENER,
BEND_AREA,
FLEX_AREA,
RIGID_AREA,
PSA,
SILVER_MASK,
CARBON_MASK,
};
enum class ODB_FID_TYPE
{
COPPER,
LAMINATE,
HOLE
};
namespace ODB
{
wxString GenODBString( const wxString& aStr );
wxString GenLegalNetName( const wxString& aStr );
wxString GenLegalEntityName( const wxString& aStr );
wxString Double2String( double aVal );
std::string Double2String( double aVal, int32_t aDigits );
wxString Data2String( double aVal );
wxString SymDouble2String( double aVal );
std::pair<wxString, wxString> AddXY( const VECTOR2I& aVec );
VECTOR2I GetShapePosition( const PCB_SHAPE& aShape );
template <typename T>
class EnumStringMap
{
public:
static std::map<T, std::string>& GetMap()
{
static_assert( std::is_enum_v<T>, "Template parameter T must be an enum type" );
static std::map<T, std::string> map = []()
{
std::map<T, std::string> result;
if constexpr( std::is_same_v<T, ODB_POLARITY> )
{
result[ODB_POLARITY::POSITIVE] = "POSITIVE";
result[ODB_POLARITY::NEGATIVE] = "NEGATIVE";
}
if constexpr( std::is_same_v<T, ODB_CONTEXT> )
{
result[ODB_CONTEXT::BOARD] = "BOARD";
result[ODB_CONTEXT::MISC] = "MISC";
}
if constexpr( std::is_same_v<T, ODB_TYPE> )
{
//just for logical reasons.TYPE field must be defined.
result[ODB_TYPE::UNDEFINED] = "";
result[ODB_TYPE::SIGNAL] = "SIGNAL";
result[ODB_TYPE::POWER_GROUND] = "POWER_GROUND";
result[ODB_TYPE::DIELECTRIC] = "DIELECTRIC";
result[ODB_TYPE::MIXED] = "MIXED";
result[ODB_TYPE::SOLDER_MASK] = "SOLDER_MASK";
result[ODB_TYPE::SOLDER_PASTE] = "SOLDER_PASTE";
result[ODB_TYPE::SILK_SCREEN] = "SILK_SCREEN";
result[ODB_TYPE::DRILL] = "DRILL";
result[ODB_TYPE::ROUT] = "ROUT";
result[ODB_TYPE::DOCUMENT] = "DOCUMENT";
result[ODB_TYPE::COMPONENT] = "COMPONENT";
result[ODB_TYPE::MASK] = "MASK";
result[ODB_TYPE::CONDUCTIVE_PASTE] = "CONDUCTIVE_PASTE";
}
if constexpr( std::is_same_v<T, ODB_SUBTYPE> )
{
result[ODB_SUBTYPE::COVERLAY] = "COVERLAY";
result[ODB_SUBTYPE::COVERCOAT] = "COVERCOAT";
result[ODB_SUBTYPE::STIFFENER] = "STIFFENER";
result[ODB_SUBTYPE::BEND_AREA] = "BEND_AREA";
result[ODB_SUBTYPE::FLEX_AREA] = "FLEX_AREA";
result[ODB_SUBTYPE::RIGID_AREA] = "RIGID_AREA";
result[ODB_SUBTYPE::PSA] = "PSA";
result[ODB_SUBTYPE::SILVER_MASK] = "SILVER_MASK";
result[ODB_SUBTYPE::CARBON_MASK] = "CARBON_MASK";
}
if constexpr( std::is_same_v<T, ODB_DIELECTRIC_TYPE> )
{
result[ODB_DIELECTRIC_TYPE::NONE] = "NONE";
result[ODB_DIELECTRIC_TYPE::PREPREG] = "PREPREG";
result[ODB_DIELECTRIC_TYPE::CORE] = "CORE";
}
if constexpr( std::is_same_v<T, ODB_FID_TYPE> )
{
result[ODB_FID_TYPE::COPPER] = "C";
result[ODB_FID_TYPE::LAMINATE] = "L";
result[ODB_FID_TYPE::HOLE] = "H";
}
return result;
}();
return map;
}
};
template <typename T>
std::string Enum2String( T value )
{
const auto& map = EnumStringMap<T>::GetMap();
auto it = map.find( value );
if( it != map.end() )
{
return it->second;
}
else
{
throw std::out_of_range( "Enum value not found in map" );
}
}
class CHECK_ONCE
{
public:
bool operator()()
{
if( first )
{
first = false;
return true;
}
return false;
}
private:
bool first = true;
};
} // namespace ODB
class ODB_TREE_WRITER;
class ODB_FILE_WRITER
{
public:
ODB_FILE_WRITER( ODB_TREE_WRITER& aTreeWriter, const wxString& aFileName );
virtual ~ODB_FILE_WRITER() { CloseFile(); }
ODB_FILE_WRITER( ODB_FILE_WRITER&& ) = delete;
ODB_FILE_WRITER& operator=( ODB_FILE_WRITER&& ) = delete;
ODB_FILE_WRITER( ODB_FILE_WRITER const& ) = delete;
ODB_FILE_WRITER& operator=( ODB_FILE_WRITER const& ) = delete;
void CreateFile( const wxString& aFileName );
bool CloseFile();
inline std::ostream& GetStream() { return m_ostream; }
private:
ODB_TREE_WRITER& m_treeWriter;
std::ofstream m_ostream;
};
class ODB_TREE_WRITER
{
public:
ODB_TREE_WRITER( const wxString& aDir ) : m_currentPath( aDir ) {}
ODB_TREE_WRITER( const wxString& aPareDir, const wxString& aSubDir )
{
CreateEntityDirectory( aPareDir, aSubDir );
}
virtual ~ODB_TREE_WRITER() {}
[[nodiscard]] ODB_FILE_WRITER CreateFileProxy( const wxString& aFileName )
{
return ODB_FILE_WRITER( *this, aFileName );
}
void CreateEntityDirectory( const wxString& aPareDir, const wxString& aSubDir = wxEmptyString );
inline const wxString GetCurrentPath() const { return m_currentPath; }
inline void SetCurrentPath( const wxString& aDir ) { m_currentPath = aDir; }
inline void SetRootPath( const wxString& aDir ) { m_rootPath = aDir; }
inline const wxString GetRootPath() const { return m_rootPath; }
private:
wxString m_currentPath;
wxString m_rootPath;
};
class ODB_TEXT_WRITER
{
public:
ODB_TEXT_WRITER( std::ostream& aStream ) : m_ostream( aStream ) {}
virtual ~ODB_TEXT_WRITER() {}
// void WriteEquationLine( const std::string &var, const std::string &value );
void WriteEquationLine( const std::string& var, int value );
void WriteEquationLine( const wxString& var, const wxString& value );
template <typename T>
void write_line_enum( const std::string& var, const T& value )
{
WriteEquationLine( var, ODB::Enum2String( value ) );
}
class ARRAY_PROXY
{
friend ODB_TEXT_WRITER;
public:
~ARRAY_PROXY();
private:
ARRAY_PROXY( ODB_TEXT_WRITER& aWriter, const std::string& aStr );
ODB_TEXT_WRITER& m_writer;
ARRAY_PROXY( ARRAY_PROXY&& ) = delete;
ARRAY_PROXY& operator=( ARRAY_PROXY&& ) = delete;
ARRAY_PROXY( ARRAY_PROXY const& ) = delete;
ARRAY_PROXY& operator=( ARRAY_PROXY const& ) = delete;
};
[[nodiscard]] ARRAY_PROXY MakeArrayProxy( const std::string& aStr )
{
return ARRAY_PROXY( *this, aStr );
}
private:
void WriteIndent();
void BeginArray( const std::string& a );
void EndArray();
std::ostream& m_ostream;
bool in_array = false;
};
class ODB_DRILL_TOOLS
{
public:
struct TOOLS
{
uint32_t m_num;
wxString m_type;
wxString m_type2 = wxT( "STANDARD" );
uint32_t m_minTol;
uint32_t m_maxTol;
wxString m_bit = wxEmptyString;
wxString m_finishSize;
wxString m_drillSize;
TOOLS() : m_num( 0 ), m_minTol( 0 ), m_maxTol( 0 ) {}
};
ODB_DRILL_TOOLS( const wxString& aUnits, const wxString& aThickness = "0",
const wxString& aUserParams = wxEmptyString );
void AddDrillTools( const wxString& aType, const wxString& aFinishSize )
{
TOOLS tool;
tool.m_num = m_tools.size() + 1;
tool.m_type = aType;
tool.m_finishSize = aFinishSize;
tool.m_drillSize = aFinishSize;
m_tools.push_back( tool );
}
void GenerateFile( std::ostream& aStream );
wxString m_units;
wxString m_thickness;
wxString m_userParams;
std::vector<ODB_DRILL_TOOLS::TOOLS> m_tools;
};
#endif // _ODB_UTIL_H_