7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2024-11-25 09:45:01 +00:00
kicad/pcbnew/pcb_io/odbpp/odb_eda_data.cpp

427 lines
12 KiB
C++

/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors.
* Author: SYSUEric <jzzhuang666@gmail.com>.
*
* 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 <build_version.h>
#include <wx/regex.h>
#include "odb_eda_data.h"
#include "hash_eda.h"
#include "netinfo.h"
#include "odb_feature.h"
#include "base_units.h"
#include "pcb_io_odbpp.h"
EDA_DATA::EDA_DATA()
{
auto& x = nets_map.emplace( std::piecewise_construct, std::forward_as_tuple( 0 ),
std::forward_as_tuple( nets.size(), "$NONE$" ) )
.first->second;
nets.push_back( &x );
}
void EDA_DATA::NET::Write( std::ostream& ost ) const
{
ost << "NET " << m_name;
WriteAttributes( ost );
ost << std::endl;
for( const auto& subnet : subnets )
{
subnet->Write( ost );
}
}
void EDA_DATA::AddNET( const NETINFO_ITEM* aNet )
{
if( nets_map.end() == nets_map.find( aNet->GetNetCode() ) )
{
wxString netName = aNet->GetNetname();
netName.Trim().Trim( false );
wxRegEx spaces( "\\s" );
spaces.Replace( &netName, "_" );
auto& net = nets_map.emplace( std::piecewise_construct,
std::forward_as_tuple( aNet->GetNetCode() ),
std::forward_as_tuple( nets.size(), netName ) )
.first->second;
nets.push_back( &net );
//TODO: netname check
}
}
void EDA_DATA::SUB_NET::Write( std::ostream& ost ) const
{
ost << "SNT ";
WriteSubnet( ost );
ost << std::endl;
for( const auto& fid : feature_ids )
{
fid.Write( ost );
}
}
void EDA_DATA::FEATURE_ID::Write( std::ostream& ost ) const
{
static const std::map<TYPE, std::string> type_map = {
{ TYPE::COPPER, "C" },
{ TYPE::HOLE, "H" },
};
ost << "FID " << type_map.at( type ) << " " << layer << " " << feature_id << std::endl;
}
void EDA_DATA::SUB_NET_VIA::WriteSubnet( std::ostream& ost ) const
{
ost << "VIA";
}
void EDA_DATA::SUB_NET_TRACE::WriteSubnet( std::ostream& ost ) const
{
ost << "TRC";
}
void EDA_DATA::SUB_NET_PLANE::WriteSubnet( std::ostream& ost ) const
{
static const std::map<FILL_TYPE, std::string> fill_type_map = { { FILL_TYPE::SOLID, "S" },
{ FILL_TYPE::OUTLINE, "O" } };
static const std::map<CUTOUT_TYPE, std::string> cutout_type_map = {
{ CUTOUT_TYPE::CIRCLE, "C" },
{ CUTOUT_TYPE::RECT, "R" },
{ CUTOUT_TYPE::OCTAGON, "O" },
{ CUTOUT_TYPE::EXACT, "E" }
};
ost << "PLN " << fill_type_map.at( fill_type ) << " " << cutout_type_map.at( cutout_type )
<< " " << fill_size;
}
void EDA_DATA::SUB_NET_TOEPRINT::WriteSubnet( std::ostream& ost ) const
{
static const std::map<SIDE, std::string> side_map = {
{ SIDE::BOTTOM, "B" },
{ SIDE::TOP, "T" },
};
ost << "TOP " << side_map.at( side ) << " " << comp_num << " " << toep_num;
}
void EDA_DATA::SUB_NET::AddFeatureID( FEATURE_ID::TYPE type, const wxString& layer,
size_t feature_id )
{
feature_ids.emplace_back( type, m_edadata->GetLyrIdx( layer ), feature_id );
}
size_t EDA_DATA::GetLyrIdx( const wxString& aLayer )
{
if( layers_map.count( aLayer ) )
{
return layers_map.at( aLayer );
}
else
{
auto idx = layers_map.size();
layers_map.emplace( aLayer, idx );
layers.push_back( aLayer );
return idx;
}
}
void OUTLINE_SQUARE::Write( std::ostream& ost ) const
{
ost << "SQ " << ODB::Data2String( m_center.x ) << " " << ODB::Data2String( m_center.y ) << " "
<< ODB::Data2String( m_halfSide ) << std::endl;
}
void OUTLINE_CIRCLE::Write( std::ostream& ost ) const
{
ost << "CR " << ODB::Data2String( m_center.x ) << " " << ODB::Data2String( m_center.y ) << " "
<< ODB::Data2String( m_radius ) << std::endl;
}
void OUTLINE_RECT::Write( std::ostream& ost ) const
{
ost << "RC " << ODB::Data2String( m_lower_left.x ) << " " << ODB::Data2String( m_lower_left.y )
<< " " << ODB::Data2String( m_width ) << " " << ODB::Data2String( m_height ) << std::endl;
}
void OUTLINE_CONTOUR::Write( std::ostream& ost ) const
{
ost << "CT" << std::endl;
m_surfaces->WriteData( ost );
ost << "CE" << std::endl;
}
void EDA_DATA::AddPackage( const FOOTPRINT* aFp )
{
// ODBPP only need unique PACKAGE in PKG record in eda/data file.
// the PKG index can repeat to be ref in CMP record in component file.
std::shared_ptr<FOOTPRINT> fp( static_cast<FOOTPRINT*>( aFp->Clone() ) );
m_eda_footprints.emplace_back( fp );
fp->SetParentGroup( nullptr );
fp->SetPosition( { 0, 0 } );
if( fp->GetLayer() != F_Cu )
fp->Flip( fp->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
fp->SetOrientation( ANGLE_0 );
size_t hash = hash_fp_item( fp.get(), HASH_POS | REL_COORD );
size_t pkg_index = packages_map.size();
wxString fp_name = fp->GetFPID().GetLibItemName().wx_str();
auto [iter, success] = packages_map.emplace( hash, PACKAGE( pkg_index, fp_name ) );
if( !success )
{
return;
}
PACKAGE* pkg = &( iter->second );
packages.push_back( pkg );
BOX2I bbox = fp->GetBoundingBox();
pkg->m_xmin = bbox.GetPosition().x;
pkg->m_ymin = bbox.GetPosition().y;
pkg->m_xmax = bbox.GetEnd().x;
pkg->m_ymax = bbox.GetEnd().y;
pkg->m_pitch = UINT64_MAX;
if( fp->Pads().size() < 2 )
pkg->m_pitch = pcbIUScale.mmToIU( 1.0 ); // placeholder value
for( size_t i = 0; i < fp->Pads().size(); ++i )
{
const PAD* pad1 = fp->Pads()[i];
for( size_t j = i + 1; j < fp->Pads().size(); ++j )
{
const PAD* pad2 = fp->Pads()[j];
const uint64_t pin_dist = ( pad1->GetCenter() - pad2->GetCenter() ).EuclideanNorm();
pkg->m_pitch = std::min( pkg->m_pitch, pin_dist );
}
}
const SHAPE_POLY_SET& courtyard = fp->GetCourtyard( F_CrtYd );
const SHAPE_POLY_SET& courtyard_back = fp->GetCourtyard( B_CrtYd );
SHAPE_POLY_SET pkg_outline;
if( courtyard.OutlineCount() > 0 )
pkg_outline = courtyard;
if( courtyard_back.OutlineCount() > 0 )
{
pkg_outline = courtyard_back;
}
if( !courtyard.OutlineCount() && !courtyard_back.OutlineCount() )
{
pkg_outline = fp->GetBoundingHull();
}
// TODO: Here we put rect, square, and circle, all as polygon
if( pkg_outline.OutlineCount() > 0 )
{
for( int ii = 0; ii < pkg_outline.OutlineCount(); ++ii )
{
pkg->m_pkgOutlines.push_back(
std::make_unique<OUTLINE_CONTOUR>( pkg_outline.Polygon( ii ) ) );
}
}
for( size_t i = 0; i < fp->Pads().size(); ++i )
{
const PAD* pad = fp->Pads()[i];
pkg->AddPin( pad, i );
}
return;
}
void EDA_DATA::PACKAGE::AddPin( const PAD* aPad, size_t aPinNum )
{
wxString name = aPad->GetNumber();
// Pins are required to have names, so if our pad doesn't have a name, we need to
// generate one that is unique
if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
name = wxString::Format( "NPTH%zu", aPinNum );
else if( name.empty() )
name = wxString::Format( "PAD%zu", aPinNum );
// // for SNT record, pad, net, pin
std::shared_ptr<PIN> pin = std::make_shared<PIN>( m_pinsVec.size(), name );
m_pinsVec.push_back( pin );
VECTOR2D relpos = aPad->GetFPRelativePosition();
pin->m_center = ODB::AddXY( relpos );
if( aPad->HasHole() )
{
pin->type = PIN::TYPE::THROUGH_HOLE;
}
else
{
pin->type = PIN::TYPE::SURFACE;
}
if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
pin->etype = PIN::ELECTRICAL_TYPE::MECHANICAL;
else if( aPad->IsOnCopperLayer() )
pin->etype = PIN::ELECTRICAL_TYPE::ELECTRICAL;
else
pin->etype = PIN::ELECTRICAL_TYPE::UNDEFINED;
if( ( aPad->HasHole() && aPad->IsOnCopperLayer() ) || aPad->GetAttribute() == PAD_ATTRIB::PTH )
{
pin->mtype = PIN::MOUNT_TYPE::THROUGH_HOLE;
}
else if( aPad->HasHole() && aPad->GetAttribute() == PAD_ATTRIB::NPTH )
{
pin->mtype = PIN::MOUNT_TYPE::HOLE;
}
else if( aPad->GetAttribute() == PAD_ATTRIB::SMD )
{
pin->mtype = PIN::MOUNT_TYPE::SMT;
}
else
{
pin->mtype = PIN::MOUNT_TYPE::UNDEFINED;
}
const std::shared_ptr<SHAPE_POLY_SET>& polygons =
aPad->GetEffectivePolygon( PADSTACK::ALL_LAYERS, ERROR_INSIDE );
// TODO: Here we put all pad shapes as polygonl, we should switch by pad shape
// Note:pad only use polygons->Polygon(0),
if( polygons->OutlineCount() > 0 )
{
pin->m_pinOutlines.push_back( std::make_unique<OUTLINE_CONTOUR>( polygons->Polygon( 0 ) ) );
}
}
void EDA_DATA::PIN::Write( std::ostream& ost ) const
{
static const std::map<TYPE, std::string> type_map = { { TYPE::SURFACE, "S" },
{ TYPE::THROUGH_HOLE, "T" },
{ TYPE::BLIND, "B" } };
static const std::map<ELECTRICAL_TYPE, std::string> etype_map = {
{ ELECTRICAL_TYPE::ELECTRICAL, "E" },
{ ELECTRICAL_TYPE::MECHANICAL, "M" },
{ ELECTRICAL_TYPE::UNDEFINED, "U" }
};
static const std::map<MOUNT_TYPE, std::string> mtype_map = { { MOUNT_TYPE::THROUGH_HOLE, "T" },
{ MOUNT_TYPE::HOLE, "H" },
{ MOUNT_TYPE::SMT, "S" },
{ MOUNT_TYPE::UNDEFINED, "U" } };
ost << "PIN " << m_name << " " << type_map.at( type ) << " " << m_center.first << " "
<< m_center.second << " 0 " << etype_map.at( etype ) << " " << mtype_map.at( mtype )
<< std::endl;
for( const auto& outline : m_pinOutlines )
{
outline->Write( ost );
}
}
void EDA_DATA::PACKAGE::Write( std::ostream& ost ) const
{
ost << "PKG " << m_name << " " << ODB::Data2String( m_pitch ) << " "
<< ODB::Data2String( m_xmin ) << " " << ODB::Data2String( m_ymin ) << " "
<< ODB::Data2String( m_xmax ) << " " << ODB::Data2String( m_ymax ) << ";" << std::endl;
for( const auto& outline : m_pkgOutlines )
{
outline->Write( ost );
}
for( const auto& pin : m_pinsVec )
{
pin->Write( ost );
}
}
void EDA_DATA::Write( std::ostream& ost ) const
{
ost << "# " << wxDateTime::Now().FormatISOCombined() << std::endl;
ost << "HDR KiCad EDA " << TO_UTF8( GetBuildVersion() ) << std::endl;
ost << "UNITS=" << PCB_IO_ODBPP::m_unitsStr << std::endl;
ost << "LYR";
for( const auto& layer : layers )
{
ost << " " << layer;
}
ost << std::endl;
WriteAttributes( ost, "#" );
for( const auto& net : nets )
{
ost << "#NET " << net->m_index << std::endl;
net->Write( ost );
}
size_t i = 0;
for( const auto* pkg : packages )
{
ost << "# PKG " << i << std::endl;
i++;
pkg->Write( ost );
ost << "#" << std::endl;
}
}