KiCad PCB EDA Suite
Loading...
Searching...
No Matches
odb_eda_data.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 * Author: SYSUEric <[email protected]>.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <build_version.h>
22
23#include "odb_eda_data.h"
24#include "hash_eda.h"
25#include "netinfo.h"
26#include "odb_feature.h"
27#include "base_units.h"
28#include "pcb_io_odbpp.h"
29
30
32{
33 auto& x = nets_map.emplace( std::piecewise_construct, std::forward_as_tuple( 0 ),
34 std::forward_as_tuple( nets.size(), "$NONE$" ) )
35 .first->second;
36
37 nets.push_back( &x );
38}
39
40
41void EDA_DATA::NET::Write( std::ostream& ost ) const
42{
43 ost << "NET " << m_name;
44
45 WriteAttributes( ost );
46
47 ost << std::endl;
48
49 for( const auto& subnet : subnets )
50 {
51 subnet->Write( ost );
52 }
53}
54
55
56void EDA_DATA::AddNET( const NETINFO_ITEM* aNet )
57{
58 if( nets_map.end() == nets_map.find( aNet->GetNetCode() ) )
59 {
60 wxString netName = aNet->GetNetname();
61 ODB::RemoveWhitespace( netName );
62
63 auto& net = nets_map.emplace( std::piecewise_construct,
64 std::forward_as_tuple( aNet->GetNetCode() ),
65 std::forward_as_tuple( nets.size(), netName ) )
66 .first->second;
67
68 nets.push_back( &net );
69
70 //TODO: netname check
71 }
72}
73
74
75void EDA_DATA::SUB_NET::Write( std::ostream& ost ) const
76{
77 ost << "SNT ";
78
79 WriteSubnet( ost );
80
81 ost << std::endl;
82
83 for( const auto& fid : feature_ids )
84 {
85 fid.Write( ost );
86 }
87}
88
89
90void EDA_DATA::FEATURE_ID::Write( std::ostream& ost ) const
91{
92 static const std::map<TYPE, std::string> type_map = {
93 { TYPE::COPPER, "C" },
94 { TYPE::HOLE, "H" },
95 };
96
97 ost << "FID " << type_map.at( type ) << " " << layer << " " << feature_id << std::endl;
98}
99
100
101void EDA_DATA::SUB_NET_VIA::WriteSubnet( std::ostream& ost ) const
102{
103 ost << "VIA";
104}
105
106
107void EDA_DATA::SUB_NET_TRACE::WriteSubnet( std::ostream& ost ) const
108{
109 ost << "TRC";
110}
111
112
113void EDA_DATA::SUB_NET_PLANE::WriteSubnet( std::ostream& ost ) const
114{
115 static const std::map<FILL_TYPE, std::string> fill_type_map = { { FILL_TYPE::SOLID, "S" },
116 { FILL_TYPE::OUTLINE, "O" } };
117
118 static const std::map<CUTOUT_TYPE, std::string> cutout_type_map = {
119 { CUTOUT_TYPE::CIRCLE, "C" },
120 { CUTOUT_TYPE::RECT, "R" },
121 { CUTOUT_TYPE::OCTAGON, "O" },
122 { CUTOUT_TYPE::EXACT, "E" }
123 };
124
125 ost << "PLN " << fill_type_map.at( fill_type ) << " " << cutout_type_map.at( cutout_type )
126 << " " << fill_size;
127}
128
129
130void EDA_DATA::SUB_NET_TOEPRINT::WriteSubnet( std::ostream& ost ) const
131{
132 static const std::map<SIDE, std::string> side_map = {
133 { SIDE::BOTTOM, "B" },
134 { SIDE::TOP, "T" },
135 };
136 ost << "TOP " << side_map.at( side ) << " " << comp_num << " " << toep_num;
137}
138
139
140void EDA_DATA::SUB_NET::AddFeatureID( FEATURE_ID::TYPE type, const wxString& layer,
141 size_t feature_id )
142{
143 feature_ids.emplace_back( type, m_edadata->GetLyrIdx( layer ), feature_id );
144}
145
146
147size_t EDA_DATA::GetLyrIdx( const wxString& aLayer )
148{
149 if( layers_map.count( aLayer ) )
150 {
151 return layers_map.at( aLayer );
152 }
153 else
154 {
155 auto idx = layers_map.size();
156 layers_map.emplace( aLayer, idx );
157 layers.push_back( aLayer );
158 return idx;
159 }
160}
161
162
163void OUTLINE_SQUARE::Write( std::ostream& ost ) const
164{
165 ost << "SQ " << ODB::Data2String( m_center.x ) << " " << ODB::Data2String( m_center.y ) << " "
166 << ODB::Data2String( m_halfSide ) << std::endl;
167}
168
169
170void OUTLINE_CIRCLE::Write( std::ostream& ost ) const
171{
172 ost << "CR " << ODB::Data2String( m_center.x ) << " " << ODB::Data2String( m_center.y ) << " "
173 << ODB::Data2String( m_radius ) << std::endl;
174}
175
176
177void OUTLINE_RECT::Write( std::ostream& ost ) const
178{
179 ost << "RC " << ODB::Data2String( m_lower_left.x ) << " " << ODB::Data2String( m_lower_left.y )
180 << " " << ODB::Data2String( m_width ) << " " << ODB::Data2String( m_height ) << std::endl;
181}
182
183
184void OUTLINE_CONTOUR::Write( std::ostream& ost ) const
185{
186 ost << "CT" << std::endl;
187 m_surfaces->WriteData( ost );
188 ost << "CE" << std::endl;
189}
190
191
193{
194 // ODBPP only need unique PACKAGE in PKG record in eda/data file.
195 // the PKG index can repeat to be ref in CMP record in component file.
196
197 std::shared_ptr<FOOTPRINT> fp( static_cast<FOOTPRINT*>( aFp->Clone() ) );
198 m_eda_footprints.emplace_back( fp );
199 fp->SetParentGroup( nullptr );
200 fp->SetPosition( { 0, 0 } );
201
202 if( aFp->IsFlipped() )
203 {
204 // ODB++ needs both flips
205 fp->Flip( fp->GetPosition(), FLIP_DIRECTION::LEFT_RIGHT );
206 fp->Flip( fp->GetPosition(), FLIP_DIRECTION::TOP_BOTTOM );
207 }
208
209 fp->SetOrientation( ANGLE_0 );
210
211 size_t hash = hash_fp_item( fp.get(), HASH_POS | REL_COORD );
212 size_t pkg_index = packages_map.size();
213 wxString fp_name = fp->GetFPID().GetLibItemName().wx_str();
214 ODB::RemoveWhitespace( fp_name );
215
216 if( fp_name.IsEmpty() )
217 fp_name = wxS( "__" );
218
219 auto [iter, success] = packages_map.emplace( hash, PACKAGE( pkg_index, fp_name ) );
220
221 if( !success )
222 {
223 return;
224 }
225
226 PACKAGE* pkg = &( iter->second );
227
228 packages.push_back( pkg );
229
230 BOX2I bbox = fp->GetBoundingBox();
231 pkg->m_xmin = bbox.GetPosition().x;
232 pkg->m_ymin = bbox.GetPosition().y;
233 pkg->m_xmax = bbox.GetEnd().x;
234 pkg->m_ymax = bbox.GetEnd().y;
235 pkg->m_pitch = UINT64_MAX;
236
237 if( fp->Pads().size() < 2 )
238 pkg->m_pitch = pcbIUScale.mmToIU( 1.0 ); // placeholder value
239
240 for( size_t i = 0; i < fp->Pads().size(); ++i )
241 {
242 const PAD* pad1 = fp->Pads()[i];
243
244 for( size_t j = i + 1; j < fp->Pads().size(); ++j )
245 {
246 const PAD* pad2 = fp->Pads()[j];
247 const uint64_t pin_dist = ( pad1->GetCenter() - pad2->GetCenter() ).EuclideanNorm();
248 pkg->m_pitch = std::min( pkg->m_pitch, pin_dist );
249 }
250 }
251
252 const SHAPE_POLY_SET& courtyard = fp->GetCourtyard( F_CrtYd );
253 const SHAPE_POLY_SET& courtyard_back = fp->GetCourtyard( B_CrtYd );
254 SHAPE_POLY_SET pkg_outline;
255
256 if( courtyard.OutlineCount() > 0 )
257 pkg_outline = courtyard;
258
259 if( courtyard_back.OutlineCount() > 0 )
260 {
261 pkg_outline = courtyard_back;
262 }
263
264 if( !courtyard.OutlineCount() && !courtyard_back.OutlineCount() )
265 {
266 pkg_outline = fp->GetBoundingHull();
267 }
268
269 // TODO: Here we put rect, square, and circle, all as polygon
270
271 if( pkg_outline.OutlineCount() > 0 )
272 {
273 for( int ii = 0; ii < pkg_outline.OutlineCount(); ++ii )
274 {
275 pkg->m_pkgOutlines.push_back(
276 std::make_unique<OUTLINE_CONTOUR>( pkg_outline.Polygon( ii ) ) );
277 }
278 }
279
280 for( size_t i = 0; i < fp->Pads().size(); ++i )
281 {
282 const PAD* pad = fp->Pads()[i];
283 pkg->AddPin( pad, i );
284 }
285
286 return;
287}
288
289
290void EDA_DATA::PACKAGE::AddPin( const PAD* aPad, size_t aPinNum )
291{
292 wxString name = aPad->GetNumber();
293
294 // ODB is unhappy with whitespace in most places
296
297 // Pins are required to have names, so if our pad doesn't have a name, we need to
298 // generate one that is unique
299
300 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
301 name = wxString::Format( "NPTH%zu", aPinNum );
302 else if( name.empty() )
303 name = wxString::Format( "PAD%zu", aPinNum );
304
305 // // for SNT record, pad, net, pin
306 std::shared_ptr<PIN> pin = std::make_shared<PIN>( m_pinsVec.size(), name );
307 m_pinsVec.push_back( pin );
308
309 VECTOR2D relpos = aPad->GetFPRelativePosition();
310
311 pin->m_center = ODB::AddXY( relpos );
312
313 if( aPad->HasHole() )
314 {
315 pin->type = PIN::TYPE::THROUGH_HOLE;
316 }
317 else
318 {
319 pin->type = PIN::TYPE::SURFACE;
320 }
321
322 if( aPad->GetAttribute() == PAD_ATTRIB::NPTH )
324 else if( aPad->IsOnCopperLayer() )
326 else
328
329
330 if( ( aPad->HasHole() && aPad->IsOnCopperLayer() ) || aPad->GetAttribute() == PAD_ATTRIB::PTH )
331 {
333 }
334 else if( aPad->HasHole() && aPad->GetAttribute() == PAD_ATTRIB::NPTH )
335 {
336 pin->mtype = PIN::MOUNT_TYPE::HOLE;
337 }
338 else if( aPad->GetAttribute() == PAD_ATTRIB::SMD )
339 {
340 pin->mtype = PIN::MOUNT_TYPE::SMT;
341 }
342 else
343 {
345 }
346
347 const std::shared_ptr<SHAPE_POLY_SET>& polygons =
349
350 // TODO: Here we put all pad shapes as polygonl, we should switch by pad shape
351 // Note:pad only use polygons->Polygon(0),
352 if( polygons->OutlineCount() > 0 )
353 {
354 pin->m_pinOutlines.push_back( std::make_unique<OUTLINE_CONTOUR>( polygons->Polygon( 0 ) ) );
355 }
356}
357
358
359void EDA_DATA::PIN::Write( std::ostream& ost ) const
360{
361 static const std::map<TYPE, std::string> type_map = { { TYPE::SURFACE, "S" },
362 { TYPE::THROUGH_HOLE, "T" },
363 { TYPE::BLIND, "B" } };
364
365 static const std::map<ELECTRICAL_TYPE, std::string> etype_map = {
366 { ELECTRICAL_TYPE::ELECTRICAL, "E" },
367 { ELECTRICAL_TYPE::MECHANICAL, "M" },
368 { ELECTRICAL_TYPE::UNDEFINED, "U" }
369 };
370 static const std::map<MOUNT_TYPE, std::string> mtype_map = { { MOUNT_TYPE::THROUGH_HOLE, "T" },
371 { MOUNT_TYPE::HOLE, "H" },
372 { MOUNT_TYPE::SMT, "S" },
373 { MOUNT_TYPE::UNDEFINED, "U" } };
374
375 ost << "PIN " << m_name << " " << type_map.at( type ) << " " << m_center.first << " "
376 << m_center.second << " 0 " << etype_map.at( etype ) << " " << mtype_map.at( mtype )
377 << std::endl;
378
379 for( const auto& outline : m_pinOutlines )
380 {
381 outline->Write( ost );
382 }
383}
384
385
386void EDA_DATA::PACKAGE::Write( std::ostream& ost ) const
387{
388 ost << "PKG " << m_name << " " << ODB::Data2String( m_pitch ) << " "
389 << ODB::Data2String( m_xmin ) << " " << ODB::Data2String( m_ymin ) << " "
390 << ODB::Data2String( m_xmax ) << " " << ODB::Data2String( m_ymax ) << ";" << std::endl;
391
392 for( const auto& outline : m_pkgOutlines )
393 {
394 outline->Write( ost );
395 }
396
397 for( const auto& pin : m_pinsVec )
398 {
399 pin->Write( ost );
400 }
401}
402
403
404void EDA_DATA::Write( std::ostream& ost ) const
405{
406 ost << "# " << wxDateTime::Now().FormatISOCombined() << std::endl;
407 ost << "HDR KiCad EDA " << TO_UTF8( GetBuildVersion() ) << std::endl;
408 ost << "UNITS=" << PCB_IO_ODBPP::m_unitsStr << std::endl;
409 ost << "LYR";
410
411 for( const auto& layer : layers )
412 {
413 ost << " " << layer;
414 }
415
416 ost << std::endl;
417
418 WriteAttributes( ost, "#" );
419
420 for( const auto& net : nets )
421 {
422 ost << "#NET " << net->m_index << std::endl;
423 net->Write( ost );
424 }
425
426 size_t i = 0;
427 for( const auto* pkg : packages )
428 {
429 ost << "# PKG " << i << std::endl;
430 i++;
431 pkg->Write( ost );
432 ost << "#" << std::endl;
433 }
434}
const char * name
Definition: DXF_plotter.cpp:59
@ ERROR_INSIDE
Definition: approximation.h:34
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
wxString GetBuildVersion()
Get the full KiCad version string.
void WriteAttributes(std::ostream &ost, const std::string &prefix="") const
void WriteAttributes(std::ostream &ost) const
VECTOR2I GetFPRelativePosition() const
Definition: board_item.cpp:327
constexpr const Vec & GetPosition() const
Definition: box2.h:211
constexpr const Vec GetEnd() const
Definition: box2.h:212
void Write(std::ostream &ost) const
void Write(std::ostream &ost) const
std::list< std::unique_ptr< SUB_NET > > subnets
Definition: odb_eda_data.h:157
wxString m_name
Definition: odb_eda_data.h:156
void AddPin(const PAD *aPad, size_t aPinNum)
void Write(std::ostream &ost) const
std::list< std::unique_ptr< PKG_OUTLINE > > m_pkgOutlines
Definition: odb_eda_data.h:238
void Write(std::ostream &ost) const
void WriteSubnet(std::ostream &ost) const override
void WriteSubnet(std::ostream &ost) const override
void WriteSubnet(std::ostream &ost) const override
void WriteSubnet(std::ostream &ost) const override
void Write(std::ostream &ost) const
void AddFeatureID(FEATURE_ID::TYPE type, const wxString &layer, size_t feature_id)
std::list< const PACKAGE * > packages
Definition: odb_eda_data.h:260
std::map< wxString, size_t > layers_map
Definition: odb_eda_data.h:262
std::list< const NET * > nets
Definition: odb_eda_data.h:257
std::map< size_t, NET > nets_map
Definition: odb_eda_data.h:256
std::vector< wxString > layers
Definition: odb_eda_data.h:263
std::map< size_t, PACKAGE > packages_map
Definition: odb_eda_data.h:259
void AddNET(const NETINFO_ITEM *aNet)
std::vector< std::shared_ptr< FOOTPRINT > > m_eda_footprints
Definition: odb_eda_data.h:264
size_t GetLyrIdx(const wxString &aLayerName)
void AddPackage(const FOOTPRINT *aFp)
void Write(std::ostream &ost) const
EDA_ITEM * Clone() const override
Invoke a function on all children.
Definition: footprint.cpp:2178
bool IsFlipped() const
Definition: footprint.h:389
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
int GetNetCode() const
Definition: netinfo.h:108
void Write(std::ostream &ost) const override
void Write(std::ostream &ost) const override
void Write(std::ostream &ost) const override
void Write(std::ostream &ost) const override
static constexpr PCB_LAYER_ID ALL_LAYERS
! Temporary layer identifier to identify code that is not padstack-aware
Definition: padstack.h:144
Definition: pad.h:54
PAD_ATTRIB GetAttribute() const
Definition: pad.h:438
const wxString & GetNumber() const
Definition: pad.h:134
VECTOR2I GetCenter() const override
This defaults to the center of the bounding box if not overridden.
Definition: pad.h:317
bool IsOnCopperLayer() const override
Definition: pad.cpp:1030
const std::shared_ptr< SHAPE_POLY_SET > & GetEffectivePolygon(PCB_LAYER_ID aLayer, ERROR_LOC aErrorLoc=ERROR_INSIDE) const
Definition: pad.cpp:499
bool HasHole() const override
Definition: pad.h:104
static std::string m_unitsStr
Definition: pcb_io_odbpp.h:144
Represent a set of closed polygons.
POLYGON & Polygon(int aIndex)
Return the aIndex-th subpolygon in the set.
int OutlineCount() const
Return the number of outlines in the set.
static constexpr EDA_ANGLE ANGLE_0
Definition: eda_angle.h:401
size_t hash_fp_item(const EDA_ITEM *aItem, int aFlags)
Calculate hash of an EDA_ITEM.
Definition: hash_eda.cpp:55
Hashing functions for EDA_ITEMs.
@ HASH_POS
Definition: hash_eda.h:47
@ REL_COORD
Use coordinates relative to the parent object.
Definition: hash_eda.h:50
@ F_CrtYd
Definition: layer_ids.h:116
@ B_CrtYd
Definition: layer_ids.h:115
wxString Data2String(double aVal)
Definition: odb_util.cpp:161
void RemoveWhitespace(wxString &aStr)
Definition: odb_util.cpp:119
std::pair< wxString, wxString > AddXY(const VECTOR2I &aVec)
Definition: odb_util.cpp:167
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:403
constexpr int mmToIU(double mm) const
Definition: base_units.h:88