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