KiCad PCB EDA Suite
Loading...
Searching...
No Matches
altium_parser_utils.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) 2021 Thomas Pointhuber <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25#include "altium_parser_utils.h"
26
27#include <string_utils.h>
28#include <lib_id.h>
29#include <trigo.h>
30#include <math/util.h>
31#include <wx/arrstr.h>
32
33LIB_ID AltiumToKiCadLibID( const wxString& aLibName, const wxString& aLibReference )
34{
35 wxString libName = LIB_ID::FixIllegalChars( aLibName, true );
36 wxString libReference = EscapeString( aLibReference, CTX_LIBID );
37
38 wxString key = !libName.empty() ? ( libName + ":" + libReference ) : libReference;
39
40 LIB_ID libId;
41 libId.Parse( key, true );
42
43 return libId;
44}
45
46
47wxString AltiumPropertyToKiCadString( const wxString& aString )
48{
49 wxString output;
50 wxString tempString;
51 bool hasPrev = false;
52 wxUniChar prev;
53
54 for( wxString::const_iterator it = aString.begin(); it != aString.end(); ++it )
55 {
56 char ch = 0;
57
58 if( (*it).GetAsChar( &ch ) )
59 {
60 if( ch == '\\' )
61 {
62 if( hasPrev )
63 {
64 tempString += prev;
65 hasPrev = false;
66 }
67
68 continue; // Backslash is ignored and not added to the output
69 }
70 }
71
72 if( hasPrev ) // Two letters in a row with no backslash
73 {
74 if( !tempString.empty() )
75 {
76 output += "~{" + tempString + "}";
77 tempString.Clear();
78 }
79
80 output += prev;
81 }
82
83 prev = *it;
84 hasPrev = true;
85 }
86
87 // Append any leftover escaped string
88 if( !tempString.IsEmpty() )
89 output += "~{" + tempString + "}";
90
91 if( hasPrev )
92 output += prev;
93
94 return output;
95}
96
97
98// https://www.altium.com/documentation/altium-designer/sch-obj-textstringtext-string-ad#!special-strings
99wxString AltiumSchSpecialStringsToKiCadVariables( const wxString& aString,
100 const std::map<wxString, wxString>& aOverrides )
101{
102 if( aString.IsEmpty() || aString.at( 0 ) != '=' )
103 {
104 return aString;
105 }
106
107 wxString result;
108
109 size_t start = 1;
110 size_t delimiter = 0;
111 size_t escaping_start = 0;
112 do
113 {
114 delimiter = aString.find( "+", start );
115 escaping_start = aString.find( "'", start );
116
117 if( escaping_start < delimiter )
118 {
119 size_t text_start = escaping_start + 1;
120 size_t escaping_end = aString.find( "'", text_start );
121
122 if( escaping_end == wxString::npos )
123 {
124 escaping_end = aString.size();
125 }
126
127 result += aString.substr( text_start, escaping_end - text_start );
128
129 start = escaping_end + 1;
130 }
131 else
132 {
133 wxString specialString =
134 aString.substr( start, delimiter - start ).Trim().Trim( false );
135
136 if( specialString.StartsWith( "\"" ) && specialString.EndsWith( "\"" ) )
137 specialString = specialString.Mid( 1, specialString.Length() - 2 );
138
139 if( !specialString.IsEmpty() )
140 {
141 // Note: Altium variable references are case-insensitive. KiCad matches
142 // case-sensitive OR to all-upper-case, so make the references all-upper-case.
143 specialString.UpperCase();
144
145 auto overrideIt = aOverrides.find( specialString );
146
147 if( overrideIt != aOverrides.end() )
148 specialString = overrideIt->second;
149
150 result += wxString::Format( wxT( "${%s}" ), specialString );
151 }
152
153 start = delimiter + 1;
154 }
155 } while( delimiter != wxString::npos );
156
157 return result;
158}
159
160
161// https://www.altium.com/documentation/altium-designer/text-objects-pcb
162wxString AltiumPcbSpecialStringsToKiCadStrings( const wxString& aString,
163 const std::map<wxString, wxString>& aOverrides )
164{
165 if( aString.IsEmpty() )
166 return aString;
167
168 // Convert a 'special string' to a KiCad variable, substituting any override.
169 const auto getVariable = [&]( const wxString& aSpecialString )
170 {
171 wxString str = aSpecialString;
172 str.UpperCase(); // matching is implemented using upper case strings
173
174 auto it = aOverrides.find( str );
175 if( it != aOverrides.end() )
176 str = it->second;
177
178 return wxString::Format( wxT( "${%s}" ), str );
179 };
180
181 // special case: string starts with dot -> whole string is special string
182 if( aString.at( 0 ) == '.' )
183 {
184 wxString specialString = aString.substr( 1 );
185 return getVariable( specialString );
186 }
187
188 // Strings can also have one or more special strings using apostrophes to
189 // delineate them, e.g. "foo '.bar' '.baz' = '.qux' quux"
190
191 // In the common case, the string is a simple string with no special strings,
192 // so bail out early.
193 if( !aString.Contains( "'." ) )
194 {
195 return aString;
196 }
197
198 wxString stringCopy = aString;
199
200 // Given a position of a dot, check if it is a special string variable
201 // and replace it with a variable name if defined.
202 const auto tryReplacement = [&]( wxString& aStr, unsigned aDotPos )
203 {
204 // Check that the dot has an apostrophe before it, if not, it's just a dot
205 if( aDotPos == 0 || aStr.at( aDotPos - 1 ) != '\'' )
206 return;
207
208 // Scan forward for the next apostrophe
209 size_t apostrophePos = aStr.find( '\'', aDotPos + 1 );
210
211 // Didn't find it
212 if( apostrophePos == wxString::npos )
213 return;
214
215 // Extract the special string
216 wxString specialString = aStr.substr( aDotPos + 1, apostrophePos - aDotPos - 1 );
217 wxString replacement = getVariable( specialString );
218
219 aStr.replace( aDotPos - 1, apostrophePos - aDotPos + 2, replacement );
220 };
221
222 // Work backwards through the string checking any dots
223 // (so we don't mess up the positions of the dots as we replace them)
224 for( size_t pos = stringCopy.size() - 1; pos > 0; --pos )
225 {
226 if( stringCopy[pos] == '.' )
227 {
228 tryReplacement( stringCopy, pos );
229 }
230 }
231
232 return stringCopy;
233}
234
235
236wxString AltiumPinNamesToKiCad( wxString& aString )
237{
238 if( aString.IsEmpty() )
239 return wxEmptyString;
240
241 wxString rest;
242
243 if( aString.StartsWith( '\\', &rest ) && !rest.Contains( '\\' ) )
244 return "~{" + rest + "}";
245
246 return AltiumPropertyToKiCadString( aString );
247}
248
249
250wxString AltiumPinDesignatorToKiCad( const wxString& aDesignator )
251{
252 wxString designator = aDesignator;
253 designator.Trim( true ).Trim( false );
254
255 if( !designator.Contains( wxT( "," ) ) )
256 return designator;
257
258 // Rebuild as KiCad stacked notation "[a,b,c]". If trimming collapses the list to a
259 // single token, emit the bare token so well-formed single designators never get wrapped.
260 wxArrayString cleaned;
261
262 for( wxString token : wxSplit( designator, ',', '\0' ) )
263 {
264 token.Trim( true ).Trim( false );
265
266 if( !token.IsEmpty() )
267 cleaned.Add( token );
268 }
269
270 if( cleaned.IsEmpty() )
271 return designator;
272
273 if( cleaned.GetCount() == 1 )
274 return cleaned[0];
275
276 return wxT( "[" ) + wxJoin( cleaned, ',', '\0' ) + wxT( "]" );
277}
278
279
280VECTOR2I AltiumGetEllipticalPos( double aMajor, double aMinor, double aAngleRadians )
281{
282 if( aMajor == 0 || aMinor == 0 )
283 return VECTOR2I( 0, 0 );
284
285 double numerator = aMajor * aMinor;
286 double majorTerm = aMajor * sin( aAngleRadians );
287 double minorTerm = aMinor * cos( aAngleRadians );
288 double denominator = sqrt( majorTerm * majorTerm + minorTerm * minorTerm );
289
290 double radius = numerator / denominator;
291
292 VECTOR2I retval( KiROUND( radius * cos( aAngleRadians ) ),
293 KiROUND( radius * sin( aAngleRadians ) ) );
294
295 return retval;
296
297}
wxString AltiumPinDesignatorToKiCad(const wxString &aDesignator)
Convert an Altium pin designator string to the equivalent KiCad pin number.
wxString AltiumSchSpecialStringsToKiCadVariables(const wxString &aString, const std::map< wxString, wxString > &aOverrides)
wxString AltiumPropertyToKiCadString(const wxString &aString)
wxString AltiumPinNamesToKiCad(wxString &aString)
VECTOR2I AltiumGetEllipticalPos(double aMajor, double aMinor, double aAngleRadians)
LIB_ID AltiumToKiCadLibID(const wxString &aLibName, const wxString &aLibReference)
wxString AltiumPcbSpecialStringsToKiCadStrings(const wxString &aString, const std::map< wxString, wxString > &aOverrides)
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:49
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition lib_id.cpp:52
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition lib_id.cpp:192
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
nlohmann::json output
int radius
wxString result
Test unit parsing edge cases and error handling.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:687