KiCad PCB EDA Suite
Loading...
Searching...
No Matches
odb_util.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 (C) 2024 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 <string>
22#include <algorithm>
23#include <locale>
24#include "odb_util.h"
25#include <wx/chartype.h>
26#include <wx/dir.h>
27#include "idf_helpers.h"
28#include "odb_defines.h"
29#include "pcb_io_odbpp.h"
30
31namespace ODB
32{
33
34wxString GenODBString( const wxString& aStr )
35{
36 wxString str;
37
38 for( size_t ii = 0; ii < aStr.Len(); ++ii )
39 {
40 // Rule: we can only use the standard ASCII, control excluded
41 wxUniChar ch = aStr[ii];
42
43 if( ch > 126 || !std::isgraph( static_cast<unsigned char>( ch ) ) )
44 ch = '?';
45
46 str += ch;
47 }
48
49 // Rule: only uppercase
50 str.MakeUpper();
51
52 return str;
53}
54
55
56wxString GenLegalNetName( const wxString& aStr )
57{
58 std::string str = aStr.ToStdString();
59 wxString out;
60 out.reserve( str.size() );
61
62 for( auto c : str )
63 {
64 if( ( c >= 33 && c <= 126 ) && c != ';' )
65 {
66 out.append( 1, c );
67 }
68 else
69 {
70 out.append( 1, '_' ); // Replace invalid characters with underscore
71 }
72 }
73
74 return out;
75}
76
77
78// The names of these ODB++ entities must comply with
79// the rules for legal entity names:
80// product, model, step, layer, symbol, and attribute.
81wxString GenLegalEntityName( const wxString& aStr )
82{
83 std::string str = aStr.ToStdString();
84 wxString out;
85 out.reserve( str.size() );
86
87 for( auto c : str )
88 {
89 if( isalpha( c ) )
90 c = tolower( c );
91 else if( isdigit( c ) || c == '-' || c == '_' || c == '+' || c == '.' )
92 ;
93 else
94 c = '_';
95
96 out.append( 1, c );
97 }
98
99 if( out.length() > 64 )
100 {
101 out.Truncate( 64 );
102 }
103
104 while( !out.IsEmpty() && ( out[0] == '.' || out[0] == '-' || out[0] == '+' ) )
105 {
106 out.erase( 0, 1 );
107 }
108
109 while( !out.IsEmpty() && out.Last() == '.' )
110 {
111 out.RemoveLast();
112 }
113
114 return out;
115}
116
117
118wxString Double2String( double aVal )
119{
120 // We don't want to output -0.0 as this value is just 0 for fabs
121 if( aVal == -0.0 )
122 aVal = 0.0;
123
124 wxString str = wxString::FromCDouble( aVal, PCB_IO_ODBPP::m_sigfig );
125
126 // Remove all but the last trailing zeros from str
127 while( str.EndsWith( wxT( "00" ) ) )
128 str.RemoveLast();
129
130 return str;
131}
132
133
134std::string Double2String( double aVal, int32_t aDigits )
135{
136 // We don't want to output -0.0 as this value is just 0 for fabs
137 if( aVal == -0.0 )
138 aVal = 0.0;
139
140 wxString str = wxString::FromCDouble( aVal, aDigits );
141
142 return str.ToStdString();
143}
144
145
146wxString SymDouble2String( double aVal )
147{
149}
150
151
152wxString Data2String( double aVal )
153{
154 return Double2String( PCB_IO_ODBPP::m_scale * aVal );
155}
156
157
158std::pair<wxString, wxString> AddXY( const VECTOR2I& aVec )
159{
160 // TODO: to deal with user preference x y increment setting
161 std::pair<wxString, wxString> xy =
162 std::pair<wxString, wxString>( Double2String( PCB_IO_ODBPP::m_scale * aVec.x ),
164
165 return xy;
166}
167
168
170{
171 VECTOR2D pos{};
172
173 switch( aShape.GetShape() )
174 {
175 // Rectangles in KiCad are mapped by their corner while ODBPP uses the center
176 case SHAPE_T::RECTANGLE:
177 pos = aShape.GetPosition()
178 + VECTOR2I( aShape.GetRectangleWidth() / 2.0, aShape.GetRectangleHeight() / 2.0 );
179 break;
180 // Both KiCad and ODBPP use the center of the circle
181 case SHAPE_T::CIRCLE:
182 // KiCad uses the exact points on the board
183 case SHAPE_T::POLY:
184 case SHAPE_T::BEZIER:
185 case SHAPE_T::SEGMENT:
186 case SHAPE_T::ARC:
187 case SHAPE_T::UNDEFINED:
188 pos = aShape.GetPosition();
189 break;
190 }
191
192 return pos;
193}
194} // namespace ODB
195
196
197void ODB_TREE_WRITER::CreateEntityDirectory( const wxString& aPareDir,
198 const wxString& aSubDir /*= wxEmptyString*/ )
199{
200 wxFileName path = wxFileName::DirName( aPareDir );
201
202 wxArrayString subDirs = wxFileName::DirName( aSubDir.Lower() ).GetDirs();
203
204 for( size_t i = 0; i < subDirs.GetCount(); i++ )
205 path.AppendDir( subDirs[i] );
206
207 if( !path.DirExists() )
208 {
209 if( !path.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
210 {
211 throw( std::runtime_error( "Could not create directory" + path.GetPath() ) );
212 }
213 }
214
215 m_currentPath = path.GetPath();
216}
217
218
219ODB_FILE_WRITER::ODB_FILE_WRITER( ODB_TREE_WRITER& aTreeWriter, const wxString& aFileName ) :
220 m_treeWriter( aTreeWriter )
221{
222 CreateFile( aFileName );
223}
224
225
226void ODB_FILE_WRITER::CreateFile( const wxString& aFileName )
227{
228 if( aFileName.IsEmpty() || m_treeWriter.GetCurrentPath().IsEmpty() )
229 return;
230
231 wxFileName fn;
232 fn.SetPath( m_treeWriter.GetCurrentPath() );
233 fn.SetFullName( aFileName );
234
235 wxString dirPath = fn.GetPath();
236
237 if( !wxDir::Exists( dirPath ) )
238 {
239 if( !wxDir::Make( dirPath ) )
240 throw( std::runtime_error( "Could not create directory" + dirPath ) );
241 }
242
243 if( !fn.IsDirWritable() || ( fn.Exists() && !fn.IsFileWritable() ) )
244 return;
245
246 if( m_ostream.is_open() )
247 m_ostream.close();
248
249 m_ostream.open( TO_UTF8( fn.GetFullPath() ),
250 std::ios_base::out | std::ios_base::trunc | std::ios_base::binary );
251
252 m_ostream.imbue( std::locale::classic() );
253
254 if( !m_ostream.is_open() || !m_ostream.good() )
255 throw std::runtime_error( "Failed to open file: " + fn.GetFullPath() );
256}
257
258
260{
261 if( m_ostream.is_open() )
262 {
263 m_ostream.close();
264
265 if( !m_ostream.good() )
266 {
267 throw std::runtime_error( "close file failed" );
268 return false;
269 }
270 }
271
272 return true;
273}
274
275
276void ODB_TEXT_WRITER::WriteEquationLine( const std::string& var, int value )
277{
278 WriteIndent();
279 m_ostream << var << "=" << value << std::endl;
280}
281
282
283void ODB_TEXT_WRITER::WriteEquationLine( const wxString& var, const wxString& value )
284{
285 WriteIndent();
286 m_ostream << var << "=" << value << std::endl;
287}
288
289
291{
292 if( in_array )
293 m_ostream << " ";
294}
295
296
297void ODB_TEXT_WRITER::BeginArray( const std::string& a )
298{
299 if( in_array )
300 throw std::runtime_error( "already in array" );
301 in_array = true;
302 m_ostream << a << " {" << std::endl;
303}
304
305
307{
308 if( !in_array )
309 throw std::runtime_error( "not in array" );
310 in_array = false;
311 m_ostream << "}" << std::endl << std::endl;
312}
313
314
315ODB_TEXT_WRITER::ARRAY_PROXY::ARRAY_PROXY( ODB_TEXT_WRITER& aWriter, const std::string& aStr ) :
316 m_writer( aWriter )
317{
318 m_writer.BeginArray( aStr );
319}
320
321
323{
324 m_writer.EndArray();
325}
326
327
328ODB_DRILL_TOOLS::ODB_DRILL_TOOLS( const wxString& aUnits, const wxString& aThickness,
329 const wxString& aUserParams ) :
330 m_units( aUnits ), m_thickness( aThickness ), m_userParams( aUserParams )
331{
332}
333
334
335void ODB_DRILL_TOOLS::GenerateFile( std::ostream& aStream )
336{
337 ODB_TEXT_WRITER twriter( aStream );
338
339 twriter.WriteEquationLine( "UNITS", m_units );
340 twriter.WriteEquationLine( "THICKNESS", m_thickness );
341 twriter.WriteEquationLine( "USER_PARAMS", m_userParams );
342
343 for( const auto& tool : m_tools )
344 {
345 const auto array_proxy = twriter.MakeArrayProxy( "TOOLS" );
346 twriter.WriteEquationLine( "NUM", tool.m_num );
347 twriter.WriteEquationLine( "TYPE", tool.m_type );
348 twriter.WriteEquationLine( "TYPE2", tool.m_type2 );
349 twriter.WriteEquationLine( "MIN_TOL", tool.m_minTol );
350 twriter.WriteEquationLine( "MAX_TOL", tool.m_maxTol );
351 twriter.WriteEquationLine( "BIT", tool.m_bit );
352 twriter.WriteEquationLine( "FINISH_SIZE", tool.m_finishSize );
353 twriter.WriteEquationLine( "DRILL_SIZE", tool.m_drillSize );
354 }
355}
int GetRectangleWidth() const
Definition: eda_shape.cpp:166
SHAPE_T GetShape() const
Definition: eda_shape.h:125
int GetRectangleHeight() const
Definition: eda_shape.cpp:153
wxString m_units
Definition: odb_util.h:349
void GenerateFile(std::ostream &aStream)
Definition: odb_util.cpp:335
ODB_DRILL_TOOLS(const wxString &aUnits, const wxString &aThickness="0", const wxString &aUserParams=wxEmptyString)
Definition: odb_util.cpp:328
wxString m_thickness
Definition: odb_util.h:350
wxString m_userParams
Definition: odb_util.h:351
std::vector< ODB_DRILL_TOOLS::TOOLS > m_tools
Definition: odb_util.h:352
void CreateFile(const wxString &aFileName)
Definition: odb_util.cpp:226
ODB_TREE_WRITER & m_treeWriter
Definition: odb_util.h:224
ODB_FILE_WRITER(ODB_TREE_WRITER &aTreeWriter, const wxString &aFileName)
Definition: odb_util.cpp:219
bool CloseFile()
Definition: odb_util.cpp:259
std::ofstream m_ostream
Definition: odb_util.h:225
ARRAY_PROXY(ODB_TEXT_WRITER &aWriter, const std::string &aStr)
Definition: odb_util.cpp:315
ODB_TEXT_WRITER & m_writer
Definition: odb_util.h:288
void WriteEquationLine(const std::string &var, int value)
Definition: odb_util.cpp:276
ARRAY_PROXY MakeArrayProxy(const std::string &aStr)
Definition: odb_util.h:299
std::ostream & m_ostream
Definition: odb_util.h:311
void BeginArray(const std::string &a)
Definition: odb_util.cpp:297
void WriteIndent()
Definition: odb_util.cpp:290
void CreateEntityDirectory(const wxString &aPareDir, const wxString &aSubDir=wxEmptyString)
Definition: odb_util.cpp:197
wxString m_currentPath
Definition: odb_util.h:258
const wxString GetCurrentPath() const
Definition: odb_util.h:248
static int m_sigfig
Definition: pcb_io_odbpp.h:143
static double m_symbolScale
Definition: pcb_io_odbpp.h:142
static double m_scale
Definition: pcb_io_odbpp.h:141
VECTOR2I GetPosition() const override
Definition: pcb_shape.h:77
Definition: odb_util.cpp:32
wxString Data2String(double aVal)
Definition: odb_util.cpp:152
wxString GenODBString(const wxString &aStr)
Definition: odb_util.cpp:34
std::pair< wxString, wxString > AddXY(const VECTOR2I &aVec)
Definition: odb_util.cpp:158
wxString GenLegalEntityName(const wxString &aStr)
Definition: odb_util.cpp:81
wxString GenLegalNetName(const wxString &aStr)
Definition: odb_util.cpp:56
wxString Double2String(double aVal)
Definition: odb_util.cpp:118
wxString SymDouble2String(double aVal)
Definition: odb_util.cpp:146
VECTOR2I GetShapePosition(const PCB_SHAPE &aShape)
Definition: odb_util.cpp:169
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
Definition: string_utils.h:398
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:691