KiCad PCB EDA Suite
altium_parser_pcb.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) 2020 Thomas Pointhuber <[email protected]>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <map>
25#include <unordered_map>
26
27#include <ki_exception.h>
28#include <math/util.h>
29
30#include <wx/log.h>
31
32#include "altium_parser_pcb.h"
34
35
36ALTIUM_LAYER altium_layer_from_name( const wxString& aName )
37{
38 static const std::unordered_map<std::string, ALTIUM_LAYER> hash_map = {
39 { "TOP", ALTIUM_LAYER::TOP_LAYER },
40 { "MID1", ALTIUM_LAYER::MID_LAYER_1 },
41 { "MID2", ALTIUM_LAYER::MID_LAYER_2 },
42 { "MID3", ALTIUM_LAYER::MID_LAYER_3 },
43 { "MID4", ALTIUM_LAYER::MID_LAYER_4 },
44 { "MID5", ALTIUM_LAYER::MID_LAYER_5 },
45 { "MID6", ALTIUM_LAYER::MID_LAYER_6 },
46 { "MID7", ALTIUM_LAYER::MID_LAYER_7 },
47 { "MID8", ALTIUM_LAYER::MID_LAYER_8 },
48 { "MID9", ALTIUM_LAYER::MID_LAYER_9 },
49 { "MID10", ALTIUM_LAYER::MID_LAYER_10 },
50 { "MID11", ALTIUM_LAYER::MID_LAYER_11 },
51 { "MID12", ALTIUM_LAYER::MID_LAYER_12 },
52 { "MID13", ALTIUM_LAYER::MID_LAYER_13 },
53 { "MID14", ALTIUM_LAYER::MID_LAYER_14 },
54 { "MID15", ALTIUM_LAYER::MID_LAYER_15 },
55 { "MID16", ALTIUM_LAYER::MID_LAYER_16 },
56 { "MID17", ALTIUM_LAYER::MID_LAYER_17 },
57 { "MID18", ALTIUM_LAYER::MID_LAYER_18 },
58 { "MID19", ALTIUM_LAYER::MID_LAYER_19 },
59 { "MID20", ALTIUM_LAYER::MID_LAYER_20 },
60 { "MID21", ALTIUM_LAYER::MID_LAYER_21 },
61 { "MID22", ALTIUM_LAYER::MID_LAYER_22 },
62 { "MID23", ALTIUM_LAYER::MID_LAYER_23 },
63 { "MID24", ALTIUM_LAYER::MID_LAYER_24 },
64 { "MID25", ALTIUM_LAYER::MID_LAYER_25 },
65 { "MID26", ALTIUM_LAYER::MID_LAYER_26 },
66 { "MID27", ALTIUM_LAYER::MID_LAYER_27 },
67 { "MID28", ALTIUM_LAYER::MID_LAYER_28 },
68 { "MID29", ALTIUM_LAYER::MID_LAYER_29 },
69 { "MID30", ALTIUM_LAYER::MID_LAYER_30 },
70 { "BOTTOM", ALTIUM_LAYER::BOTTOM_LAYER },
71
72 { "TOPOVERLAY", ALTIUM_LAYER::TOP_OVERLAY },
73 { "BOTTOMOVERLAY", ALTIUM_LAYER::BOTTOM_OVERLAY },
74 { "TOPPASTE", ALTIUM_LAYER::TOP_PASTE },
75 { "BOTTOMPASTE", ALTIUM_LAYER::BOTTOM_PASTE },
76 { "TOPSOLDER", ALTIUM_LAYER::TOP_SOLDER },
77 { "BOTTOMSOLDER", ALTIUM_LAYER::BOTTOM_SOLDER },
78
95
96 { "DRILLGUIDE", ALTIUM_LAYER::DRILL_GUIDE },
97 { "KEEPOUT", ALTIUM_LAYER::KEEP_OUT_LAYER },
98
99 { "MECHANICAL1", ALTIUM_LAYER::MECHANICAL_1 },
100 { "MECHANICAL2", ALTIUM_LAYER::MECHANICAL_2 },
101 { "MECHANICAL3", ALTIUM_LAYER::MECHANICAL_3 },
102 { "MECHANICAL4", ALTIUM_LAYER::MECHANICAL_4 },
103 { "MECHANICAL5", ALTIUM_LAYER::MECHANICAL_5 },
104 { "MECHANICAL6", ALTIUM_LAYER::MECHANICAL_6 },
105 { "MECHANICAL7", ALTIUM_LAYER::MECHANICAL_7 },
106 { "MECHANICAL8", ALTIUM_LAYER::MECHANICAL_8 },
107 { "MECHANICAL9", ALTIUM_LAYER::MECHANICAL_9 },
108 { "MECHANICAL10", ALTIUM_LAYER::MECHANICAL_10 },
109 { "MECHANICAL11", ALTIUM_LAYER::MECHANICAL_11 },
110 { "MECHANICAL12", ALTIUM_LAYER::MECHANICAL_12 },
111 { "MECHANICAL13", ALTIUM_LAYER::MECHANICAL_13 },
112 { "MECHANICAL14", ALTIUM_LAYER::MECHANICAL_14 },
113 { "MECHANICAL15", ALTIUM_LAYER::MECHANICAL_15 },
114 { "MECHANICAL16", ALTIUM_LAYER::MECHANICAL_16 },
115
116 { "DRILLDRAWING", ALTIUM_LAYER::DRILL_DRAWING },
117 { "MULTILAYER", ALTIUM_LAYER::MULTI_LAYER },
118
119 // FIXME: the following mapping is just a guess
120 { "CONNECTIONS", ALTIUM_LAYER::CONNECTIONS },
121 { "BACKGROUND", ALTIUM_LAYER::BACKGROUND },
122 { "DRCERRORMARKERS", ALTIUM_LAYER::DRC_ERROR_MARKERS },
123 { "SELECTIONS", ALTIUM_LAYER::SELECTIONS },
124 { "VISIBLEGRID1", ALTIUM_LAYER::VISIBLE_GRID_1 },
125 { "VISIBLEGRID2", ALTIUM_LAYER::VISIBLE_GRID_2 },
126 { "PADHOLES", ALTIUM_LAYER::PAD_HOLES },
127 { "VIAHOLES", ALTIUM_LAYER::VIA_HOLES },
128 };
129
130 auto it = hash_map.find( std::string( aName.c_str() ) );
131
132 if( it == hash_map.end() )
133 {
134 wxLogError( _( "Unknown mapping of the Altium layer '%s'." ), aName );
136 }
137 else
138 {
139 return it->second;
140 }
141}
142
143void altium_parse_polygons( std::map<wxString, wxString>& aProps,
144 std::vector<ALTIUM_VERTICE>& aVertices )
145{
146 for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
147 {
148 const wxString si = std::to_string( i );
149
150 const wxString vxi = wxT( "VX" ) + si;
151 const wxString vyi = wxT( "VY" ) + si;
152
153 if( aProps.find( vxi ) == aProps.end() || aProps.find( vyi ) == aProps.end() )
154 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
155
156 const bool isRound = ALTIUM_PARSER::ReadInt( aProps, wxT( "KIND" ) + si, 0 ) != 0;
157 const int32_t radius = ALTIUM_PARSER::ReadKicadUnit( aProps, wxT( "R" ) + si, wxT( "0mil" ) );
158 const double sa = ALTIUM_PARSER::ReadDouble( aProps, wxT( "SA" ) + si, 0. );
159 const double ea = ALTIUM_PARSER::ReadDouble( aProps, wxT( "EA" ) + si, 0. );
160 const VECTOR2I vp = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( aProps, vxi, wxT( "0mil" ) ),
161 -ALTIUM_PARSER::ReadKicadUnit( aProps, vyi, wxT( "0mil" ) ) );
162 const VECTOR2I cp = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( aProps, wxT( "CX" ) + si, wxT( "0mil" ) ),
163 -ALTIUM_PARSER::ReadKicadUnit( aProps, wxT( "CY" ) + si, wxT( "0mil" ) ) );
164
165 aVertices.emplace_back( isRound, radius, sa, ea, vp, cp );
166 }
167}
168
169
170static ALTIUM_MODE ReadAltiumModeFromProperties( const std::map<wxString, wxString>& aProps,
171 wxString aKey )
172{
173 wxString mode = ALTIUM_PARSER::ReadString( aProps, aKey, wxT( "" ) );
174
175 if( mode == wxT( "None" ) )
176 return ALTIUM_MODE::NONE;
177 else if( mode == wxT( "Rule" ) )
178 return ALTIUM_MODE::RULE;
179 else if( mode == wxT( "Manual" ) )
180 return ALTIUM_MODE::MANUAL;
181
182 wxLogError( _( "Unknown Mode string: '%s'." ), mode );
184}
185
186
187static ALTIUM_RECORD ReadAltiumRecordFromProperties( const std::map<wxString, wxString>& aProps,
188 wxString aKey )
189{
190 wxString record = ALTIUM_PARSER::ReadString( aProps, aKey, wxT( "" ) );
191
192 if( record == wxT( "Arc" ) )
193 return ALTIUM_RECORD::ARC;
194 else if( record == wxT( "Pad" ) )
195 return ALTIUM_RECORD::PAD;
196 else if( record == wxT( "Via" ) )
197 return ALTIUM_RECORD::VIA;
198 else if( record == wxT( "Track" ) )
200 else if( record == wxT( "Text" ) )
201 return ALTIUM_RECORD::TEXT;
202 else if( record == wxT( "Fill" ) )
203 return ALTIUM_RECORD::FILL;
204 else if( record == wxT( "Region" ) ) // correct?
206 else if( record == wxT( "Model" ) )
208
209 wxLogError( _( "Unknown Record name string: '%s'." ), record );
211}
212
213
216 const std::map<wxString, wxString>& aProps, wxString aKey )
217{
218 wxString parsedType = ALTIUM_PARSER::ReadString( aProps, aKey, wxT( "" ) );
219
220 if( parsedType == wxT( "Mask" ) )
222
223 wxLogError( _( "Unknown Extended Primitive Information type: '%s'." ), parsedType );
225}
226
227
229{
230 const std::map<wxString, wxString> props = aReader.ReadProperties();
231
232 if( props.empty() )
233 THROW_IO_ERROR( wxT( "ExtendedPrimitiveInformation stream has no properties!" ) );
234
235 primitiveIndex = ALTIUM_PARSER::ReadInt( props, wxT( "PRIMITIVEINDEX" ), -1 );
236 primitiveObjectId = ReadAltiumRecordFromProperties( props, wxT( "PRIMITIVEOBJECTID" ) );
238
239 pastemaskexpansionmode = ReadAltiumModeFromProperties( props, wxT( "PASTEMASKEXPANSIONMODE" ) );
241 props, wxT( "PASTEMASKEXPANSION_MANUAL" ), wxT( "0mil" ) );
243 ReadAltiumModeFromProperties( props, wxT( "SOLDERMASKEXPANSIONMODE" ) );
245 props, wxT( "SOLDERMASKEXPANSION_MANUAL" ), wxT( "0mil" ) );
246}
247
248
250{
251 std::map<wxString, wxString> props = aReader.ReadProperties();
252
253 if( props.empty() )
254 THROW_IO_ERROR( wxT( "Board6 stream has no properties!" ) );
255
256 sheetpos = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETX" ), wxT( "0mil" ) ),
257 -ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETY" ), wxT( "0mil" ) ) );
258 sheetsize = wxSize( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETWIDTH" ), wxT( "0mil" ) ),
259 ALTIUM_PARSER::ReadKicadUnit( props, wxT( "SHEETHEIGHT" ), wxT( "0mil" ) ) );
260
261 layercount = ALTIUM_PARSER::ReadInt( props, wxT( "LAYERSETSCOUNT" ), 1 ) + 1;
262
263 for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
264 {
265 const wxString layeri = wxT( "LAYER" ) + std::to_string( i );
266 const wxString layername = layeri + wxT( "NAME" );
267
268 auto layernameit = props.find( layername );
269
270 if( layernameit == props.end() )
271 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
272
274
275 l.name = ALTIUM_PARSER::ReadString( props, layername, wxT( "" ) );
276 l.nextId = ALTIUM_PARSER::ReadInt( props, layeri + wxT( "NEXT" ), 0 );
277 l.prevId = ALTIUM_PARSER::ReadInt( props, layeri + wxT( "PREV" ), 0 );
278 l.copperthick = ALTIUM_PARSER::ReadKicadUnit( props, layeri + wxT( "COPTHICK" ), wxT( "1.4mil" ) );
279
280 l.dielectricconst = ALTIUM_PARSER::ReadDouble( props, layeri + wxT( "DIELCONST" ), 0. );
281 l.dielectricthick = ALTIUM_PARSER::ReadKicadUnit( props, layeri + wxT( "DIELHEIGHT" ), wxT( "60mil" ) );
282 l.dielectricmaterial = ALTIUM_PARSER::ReadString( props, layeri + wxT( "DIELMATERIAL" ), wxT( "FR-4" ) );
283
284 stackup.push_back( l );
285 }
286
288
289 if( aReader.HasParsingError() )
290 THROW_IO_ERROR( wxT( "Board6 stream was not parsed correctly!" ) );
291}
292
294{
295 std::map<wxString, wxString> properties = aReader.ReadProperties();
296
297 if( properties.empty() )
298 THROW_IO_ERROR( wxT( "Classes6 stream has no properties!" ) );
299
300 name = ALTIUM_PARSER::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
301 uniqueid = ALTIUM_PARSER::ReadString( properties, wxT( "UNIQUEID" ), wxT( "" ) );
302 kind = static_cast<ALTIUM_CLASS_KIND>( ALTIUM_PARSER::ReadInt( properties, wxT( "KIND" ), -1 ) );
303
304 for( size_t i = 0; i < std::numeric_limits<size_t>::max(); i++ )
305 {
306 auto mit = properties.find( wxT( "M" ) + std::to_string( i ) );
307
308 if( mit == properties.end() )
309 break; // it doesn't seem like we know beforehand how many components are in the netclass
310
311 names.push_back( mit->second );
312 }
313
314 if( aReader.HasParsingError() )
315 THROW_IO_ERROR( wxT( "Classes6 stream was not parsed correctly" ) );
316}
317
319{
320 std::map<wxString, wxString> props = aReader.ReadProperties();
321
322 if( props.empty() )
323 THROW_IO_ERROR( wxT( "Components6 stream has no props" ) );
324
325 layer = altium_layer_from_name( ALTIUM_PARSER::ReadString( props, wxT( "LAYER" ), wxT( "" ) ) );
326 position = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "X" ), wxT( "0mil" ) ),
327 -ALTIUM_PARSER::ReadKicadUnit( props, wxT( "Y" ), wxT( "0mil" ) ) );
328 rotation = ALTIUM_PARSER::ReadDouble( props, wxT( "ROTATION" ), 0. );
329 locked = ALTIUM_PARSER::ReadBool( props, wxT( "LOCKED" ), false );
330 nameon = ALTIUM_PARSER::ReadBool( props, wxT( "NAMEON" ), true );
331 commenton = ALTIUM_PARSER::ReadBool( props, wxT( "COMMENTON" ), false );
332 sourcedesignator = ALTIUM_PARSER::ReadString( props, wxT( "SOURCEDESIGNATOR" ), wxT( "" ) );
333 sourcefootprintlibrary = ALTIUM_PARSER::ReadString( props, wxT( "SOURCEFOOTPRINTLIBRARY" ), wxT( "" ) );
334 pattern = ALTIUM_PARSER::ReadString( props, wxT( "PATTERN" ), wxT( "" ) );
335
336 sourcecomponentlibrary = ALTIUM_PARSER::ReadString( props, wxT( "SOURCECOMPONENTLIBRARY" ), wxT( "" ) );
337 sourcelibreference = ALTIUM_PARSER::ReadString( props, wxT( "SOURCELIBREFERENCE" ), wxT( "" ) );
338
340 ALTIUM_PARSER::ReadInt( props, wxT( "NAMEAUTOPOSITION" ), 0 ) );
342 ALTIUM_PARSER::ReadInt( props, wxT( "COMMENTAUTOPOSITION" ), 0 ) );
343
344 if( aReader.HasParsingError() )
345 THROW_IO_ERROR( wxT( "Components6 stream was not parsed correctly" ) );
346}
347
349{
350 aReader.Skip( 2 );
351
352 std::map<wxString, wxString> props = aReader.ReadProperties();
353
354 if( props.empty() )
355 THROW_IO_ERROR( wxT( "Dimensions6 stream has no props" ) );
356
357 layer = altium_layer_from_name( ALTIUM_PARSER::ReadString( props, wxT( "LAYER" ), wxT( "" ) ) );
358 kind = static_cast<ALTIUM_DIMENSION_KIND>( ALTIUM_PARSER::ReadInt( props, wxT( "DIMENSIONKIND" ), 0 ) );
359
360 textformat = ALTIUM_PARSER::ReadString( props, wxT( "TEXTFORMAT" ), wxT( "" ) );
361 textprefix = ALTIUM_PARSER::ReadString( props, wxT( "TEXTPREFIX" ), wxT( "" ) );
362 textsuffix = ALTIUM_PARSER::ReadString( props, wxT( "TEXTSUFFIX" ), wxT( "" ) );
363
364 height = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "HEIGHT" ), wxT( "0mil" ) );
365 angle = ALTIUM_PARSER::ReadDouble( props, wxT( "ANGLE" ), 0. );
366
367 linewidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "LINEWIDTH" ), wxT( "10mil" ) );
368 textheight = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "TEXTHEIGHT" ), wxT( "10mil" ) );
369 textlinewidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "TEXTLINEWIDTH" ), wxT( "6mil" ) );
370 textprecision = ALTIUM_PARSER::ReadInt( props, wxT( "TEXTPRECISION" ), 2 );
371 textbold = ALTIUM_PARSER::ReadBool( props, wxT( "TEXTLINEWIDTH" ), false );
372 textitalic = ALTIUM_PARSER::ReadBool( props, wxT( "ITALIC" ), false );
373 textgap = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "TEXTGAP" ), wxT( "10mil" ) );
374
375 arrowsize = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "ARROWSIZE" ), wxT( "60mil" ) );
376
377 wxString text_position_raw = ALTIUM_PARSER::ReadString( props, wxT( "TEXTPOSITION" ), wxT( "" ) );
378
379 xy1 = VECTOR2I( ALTIUM_PARSER::ReadKicadUnit( props, wxT( "X1" ), wxT( "0mil" ) ),
380 -ALTIUM_PARSER::ReadKicadUnit( props, wxT( "Y1" ), wxT( "0mil" ) ) );
381
382 int refcount = ALTIUM_PARSER::ReadInt( props, wxT( "REFERENCES_COUNT" ), 0 );
383
384 for( int i = 0; i < refcount; i++ )
385 {
386 const std::string refi = "REFERENCE" + std::to_string( i ) + "POINT";
387 referencePoint.emplace_back( ALTIUM_PARSER::ReadKicadUnit( props, refi + wxT( "X" ), wxT( "0mil" ) ),
388 -ALTIUM_PARSER::ReadKicadUnit( props, refi + wxT( "Y" ), wxT( "0mil" ) ) );
389 }
390
391 for( size_t i = 1; i < std::numeric_limits<size_t>::max(); i++ )
392 {
393 const std::string texti = "TEXT" + std::to_string( i );
394 const std::string textix = texti + "X";
395 const std::string textiy = texti + "Y";
396
397 if( props.find( textix ) == props.end() || props.find( textiy ) == props.end() )
398 break; // it doesn't seem like we know beforehand how many vertices are inside a polygon
399
400 textPoint.emplace_back( ALTIUM_PARSER::ReadKicadUnit( props, textix, wxT( "0mil" ) ),
401 -ALTIUM_PARSER::ReadKicadUnit( props, textiy, wxT( "0mil" ) ) );
402 }
403
404 wxString dimensionunit = ALTIUM_PARSER::ReadString( props, wxT( "TEXTDIMENSIONUNIT" ), wxT( "Millimeters" ) );
405
406 if( dimensionunit == wxT( "Inches" ) ) textunit = ALTIUM_UNIT::INCHES;
407 else if( dimensionunit == wxT( "Mils" ) ) textunit = ALTIUM_UNIT::MILS;
408 else if( dimensionunit == wxT( "Millimeters" ) ) textunit = ALTIUM_UNIT::MILLIMETERS;
409 else if( dimensionunit == wxT( "Centimeters" ) ) textunit = ALTIUM_UNIT::CENTIMETER;
411
412 if( aReader.HasParsingError() )
413 THROW_IO_ERROR( wxT( "Dimensions6 stream was not parsed correctly" ) );
414}
415
417{
418 std::map<wxString, wxString> properties = aReader.ReadProperties();
419
420 if( properties.empty() )
421 THROW_IO_ERROR( wxT( "Model stream has no properties!" ) );
422
423 name = ALTIUM_PARSER::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
424 id = ALTIUM_PARSER::ReadString( properties, wxT( "ID" ), wxT( "" ) );
425 isEmbedded = ALTIUM_PARSER::ReadBool( properties, wxT( "EMBED" ), false );
426
427 rotation.x = ALTIUM_PARSER::ReadDouble( properties, wxT( "ROTX" ), 0. );
428 rotation.y = ALTIUM_PARSER::ReadDouble( properties, wxT( "ROTY" ), 0. );
429 rotation.z = ALTIUM_PARSER::ReadDouble( properties, wxT( "ROTZ" ), 0. );
430
431 if( aReader.HasParsingError() )
432 THROW_IO_ERROR( wxT( "Model stream was not parsed correctly" ) );
433}
434
436{
437 std::map<wxString, wxString> properties = aReader.ReadProperties();
438
439 if( properties.empty() )
440 THROW_IO_ERROR( wxT( "Nets6 stream has no properties" ) );
441
442 name = ALTIUM_PARSER::ReadString( properties, wxT( "NAME" ), wxT( "" ) );
443
444 if( aReader.HasParsingError() )
445 THROW_IO_ERROR( wxT( "Nets6 stream was not parsed correctly" ) );
446}
447
449{
450 std::map<wxString, wxString> properties = aReader.ReadProperties();
451
452 if( properties.empty() )
453 THROW_IO_ERROR( wxT( "Polygons6 stream has no properties" ) );
454
455 layer = altium_layer_from_name( ALTIUM_PARSER::ReadString( properties, wxT( "LAYER" ), wxT( "" ) ) );
456 net = ALTIUM_PARSER::ReadInt( properties, wxT( "NET" ), ALTIUM_NET_UNCONNECTED );
457 locked = ALTIUM_PARSER::ReadBool( properties, wxT( "LOCKED" ), false );
458
459 // TODO: kind
460
461 gridsize = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "GRIDSIZE" ), wxT( "0mil" ) );
462 trackwidth = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "TRACKWIDTH" ), wxT( "0mil" ) );
463 minprimlength = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MINPRIMLENGTH" ), wxT( "0mil" ) );
464 useoctagons = ALTIUM_PARSER::ReadBool( properties, wxT( "USEOCTAGONS" ), false );
465
466 pourindex = ALTIUM_PARSER::ReadInt( properties, wxT( "POURINDEX" ), 0 );
467
468 wxString hatchstyleraw = ALTIUM_PARSER::ReadString( properties, wxT( "HATCHSTYLE" ), wxT( "" ) );
469
470 if( hatchstyleraw == wxT( "Solid" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::SOLID;
471 else if( hatchstyleraw == wxT( "45Degree" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_45;
472 else if( hatchstyleraw == wxT( "90Degree" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::DEGREE_90;
473 else if( hatchstyleraw == wxT( "Horizontal" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::HORIZONTAL;
474 else if( hatchstyleraw == wxT( "Vertical" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::VERTICAL;
475 else if( hatchstyleraw == wxT( "None" ) ) hatchstyle = ALTIUM_POLYGON_HATCHSTYLE::NONE;
477
478 altium_parse_polygons( properties, vertices );
479
480 if( aReader.HasParsingError() )
481 THROW_IO_ERROR( wxT( "Polygons6 stream was not parsed correctly" ) );
482}
483
485{
486 // Initialize all variables and make Coverity happy
487 clearanceGap = 0;
493
494 aReader.Skip( 2 );
495
496 std::map<wxString, wxString> props = aReader.ReadProperties();
497
498 if( props.empty() )
499 THROW_IO_ERROR( wxT( "Rules6 stream has no props" ) );
500
501 name = ALTIUM_PARSER::ReadString( props, wxT( "NAME" ), wxT( "" ) );
502 priority = ALTIUM_PARSER::ReadInt( props, wxT( "PRIORITY" ), 1 );
503
504 scope1expr = ALTIUM_PARSER::ReadString( props, wxT( "SCOPE1EXPRESSION" ), wxT( "" ) );
505 scope2expr = ALTIUM_PARSER::ReadString( props, wxT( "SCOPE2EXPRESSION" ), wxT( "" ) );
506
507 wxString rulekind = ALTIUM_PARSER::ReadString( props, wxT( "RULEKIND" ), wxT( "" ) );
508 if( rulekind == wxT( "Clearance" ) )
509 {
511 clearanceGap = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "GAP" ), wxT( "10mil" ) );
512 }
513 else if( rulekind == wxT( "DiffPairsRouting" ) )
514 {
516 }
517 else if( rulekind == wxT( "Height" ) )
518 {
520 }
521 else if( rulekind == wxT( "HoleSize" ) )
522 {
524 }
525 else if( rulekind == wxT( "HoleToHoleClearance" ) )
526 {
528 }
529 else if( rulekind == wxT( "Width" ) )
530 {
532 }
533 else if( rulekind == wxT( "PasteMaskExpansion" ) )
534 {
536 }
537 else if( rulekind == wxT( "PlaneClearance" ) )
538 {
540 planeclearanceClearance = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "CLEARANCE" ), wxT( "10mil" ) );
541 }
542 else if( rulekind == wxT( "PolygonConnect" ) )
543 {
545 polygonconnectAirgapwidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "AIRGAPWIDTH" ), wxT( "10mil" ) );
546 polygonconnectReliefconductorwidth = ALTIUM_PARSER::ReadKicadUnit( props, wxT( "RELIEFCONDUCTORWIDTH" ), wxT( "10mil" ) );
547 polygonconnectReliefentries = ALTIUM_PARSER::ReadInt( props, wxT( "RELIEFENTRIES" ), 4 );
548
549 wxString style = ALTIUM_PARSER::ReadString( props, wxT( "CONNECTSTYLE" ), wxT( "" ) );
550
551 if( style == wxT( "Direct" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::DIRECT;
552 else if( style == wxT( "Relief" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::RELIEF;
553 else if( style == wxT( "NoConnect" ) ) polygonconnectStyle = ALTIUM_CONNECT_STYLE::NONE;
555 }
556 else
557 {
559 }
560
561 if( aReader.HasParsingError() )
562 THROW_IO_ERROR( wxT( "Rules6 stream was not parsed correctly" ) );
563}
564
566{
567 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
568 if( recordtype != ALTIUM_RECORD::ARC )
569 {
570 THROW_IO_ERROR( wxT( "Arcs6 stream has invalid recordtype" ) );
571 }
572
573 // Subrecord 1
575
576 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
577
578 uint8_t flags1 = aReader.Read<uint8_t>();
579 is_locked = ( flags1 & 0x04 ) == 0;
580 is_polygonoutline = ( flags1 & 0x02 ) != 0;
581
582 uint8_t flags2 = aReader.Read<uint8_t>();
583 is_keepout = flags2 == 2;
584
585 net = aReader.Read<uint16_t>();
586 subpolyindex = aReader.Read<uint16_t>();
587 component = aReader.Read<uint16_t>();
588 aReader.Skip( 4 );
589 center = aReader.ReadVector2IPos();
590 radius = aReader.ReadKicadUnit();
591 startangle = aReader.Read<double>();
592 endangle = aReader.Read<double>();
593 width = aReader.ReadKicadUnit();
594
595 if( aReader.GetRemainingSubrecordBytes() >= 12 )
596 {
597 aReader.Skip( 11 );
598 keepoutrestrictions = aReader.Read<uint8_t>();
599 }
600 else
601 {
602 keepoutrestrictions = is_keepout ? 0x1F : 0;
603 }
604
605 aReader.SkipSubrecord();
606
607 if( aReader.HasParsingError() )
608 {
609 THROW_IO_ERROR( wxT( "Arcs6 stream was not parsed correctly" ) );
610 }
611}
612
614{
615 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
616
617 if( recordtype != ALTIUM_RECORD::MODEL )
618 THROW_IO_ERROR( wxT( "ComponentsBodies6 stream has invalid recordtype" ) );
619
621
622 aReader.Skip( 7 );
623 component = aReader.Read<uint16_t>();
624 aReader.Skip( 9 );
625
626 std::map<wxString, wxString> properties = aReader.ReadProperties();
627
628 if( properties.empty() )
629 THROW_IO_ERROR( wxT( "ComponentsBodies6 stream has no properties" ) );
630
631 modelName = ALTIUM_PARSER::ReadString( properties, wxT( "MODEL.NAME" ), wxT( "" ) );
632 modelId = ALTIUM_PARSER::ReadString( properties, wxT( "MODELID" ), wxT( "" ) );
633 modelIsEmbedded = ALTIUM_PARSER::ReadBool( properties, wxT( "MODEL.EMBED" ), false );
634
635 modelPosition.x = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MODEL.2D.X" ), wxT( "0mil" ) );
636 modelPosition.y = -ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MODEL.2D.Y" ), wxT( "0mil" ) );
637 modelPosition.z = ALTIUM_PARSER::ReadKicadUnit( properties, wxT( "MODEL.3D.DZ" ), wxT( "0mil" ) );
638
639 modelRotation.x = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.3D.ROTX" ), 0. );
640 modelRotation.y = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.3D.ROTY" ), 0. );
641 modelRotation.z = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.3D.ROTZ" ), 0. );
642
643 rotation = ALTIUM_PARSER::ReadDouble( properties, wxT( "MODEL.2D.ROTATION" ), 0. );
644
645 bodyOpacity = ALTIUM_PARSER::ReadDouble( properties, wxT( "BODYOPACITY3D" ), 1. );
646
647 aReader.SkipSubrecord();
648
649 if( aReader.HasParsingError() )
650 THROW_IO_ERROR( wxT( "Components6 stream was not parsed correctly" ) );
651}
652
654{
655 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
656
657 if( recordtype != ALTIUM_RECORD::PAD )
658 THROW_IO_ERROR( wxT( "Pads6 stream has invalid recordtype" ) );
659
660 // Subrecord 1
661 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
662
663 if( subrecord1 == 0 )
664 THROW_IO_ERROR( wxT( "Pads6 stream has no subrecord1 data" ) );
665
666 name = aReader.ReadWxString();
667
668 if( aReader.GetRemainingSubrecordBytes() != 0 )
669 THROW_IO_ERROR( wxT( "Pads6 stream has invalid subrecord1 length" ) );
670
671 aReader.SkipSubrecord();
672
673 // Subrecord 2
675 aReader.SkipSubrecord();
676
677 // Subrecord 3
679 aReader.SkipSubrecord();
680
681 // Subrecord 4
683 aReader.SkipSubrecord();
684
685 // Subrecord 5
686 size_t subrecord5 = aReader.ReadAndSetSubrecordLength();
687
688 if( subrecord5 < 114 )
689 THROW_IO_ERROR( wxT( "Pads6 stream subrecord has length < 114, which is unexpected" ) );
690
691 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
694
695 uint8_t flags1 = aReader.Read<uint8_t>();
696 is_test_fab_top = ( flags1 & 0x80 ) != 0;
697 is_tent_bottom = ( flags1 & 0x40 ) != 0;
698 is_tent_top = ( flags1 & 0x20 ) != 0;
699 is_locked = ( flags1 & 0x04 ) == 0;
700
701 uint8_t flags2 = aReader.Read<uint8_t>();
702 is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
703
704 net = aReader.Read<uint16_t>();
705 aReader.Skip( 2 );
706 component = aReader.Read<uint16_t>();
707 aReader.Skip( 4 );
708
709 position = aReader.ReadVector2IPos();
710 topsize = aReader.ReadVector2ISize();
711 midsize = aReader.ReadVector2ISize();
712 botsize = aReader.ReadVector2ISize();
713 holesize = aReader.ReadKicadUnit();
714
715 topshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
716 midshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
717 botshape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
718
719 direction = aReader.Read<double>();
720 plated = aReader.Read<uint8_t>() != 0;
721 aReader.Skip( 1 );
722 padmode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
723 aReader.Skip( 23 );
726 aReader.Skip( 7 );
727 pastemaskexpansionmode = static_cast<ALTIUM_MODE>( aReader.Read<uint8_t>() );
728 soldermaskexpansionmode = static_cast<ALTIUM_MODE>( aReader.Read<uint8_t>() );
729 aReader.Skip( 3 );
730 holerotation = aReader.Read<double>();
731
732 if( subrecord5 >= 120 )
733 {
734 tolayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
735 aReader.Skip( 2 );
736 fromlayer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
737 //aReader.skip( 2 );
738 }
739 else if( subrecord5 == 171 )
740 {
741 }
742
743 aReader.SkipSubrecord();
744
745 // Subrecord 6
746 size_t subrecord6 = aReader.ReadAndSetSubrecordLength();
747 // Known lengths: 596, 628, 651
748 // 596 is the number of bytes read in this code-block
749 if( subrecord6 >= 596 )
750 { // TODO: detect type from something else than the size?
751 sizeAndShape = std::make_unique<APAD6_SIZE_AND_SHAPE>();
752
753 for( wxSize& size : sizeAndShape->inner_size )
754 size.x = aReader.ReadKicadUnitX();
755
756 for( wxSize& size : sizeAndShape->inner_size )
757 size.y = aReader.ReadKicadUnitY();
758
759 for( ALTIUM_PAD_SHAPE& shape : sizeAndShape->inner_shape )
760 shape = static_cast<ALTIUM_PAD_SHAPE>( aReader.Read<uint8_t>() );
761
762 aReader.Skip( 1 );
763
764 sizeAndShape->holeshape = static_cast<ALTIUM_PAD_HOLE_SHAPE>( aReader.Read<uint8_t>() );
765 sizeAndShape->slotsize = aReader.ReadKicadUnit();
766 sizeAndShape->slotrotation = aReader.Read<double>();
767
768 for( VECTOR2I& pt : sizeAndShape->holeoffset )
769 pt.x = aReader.ReadKicadUnitX();
770
771 for( VECTOR2I& pt : sizeAndShape->holeoffset )
772 pt.y = aReader.ReadKicadUnitY();
773
774 aReader.Skip( 1 );
775
776 for( ALTIUM_PAD_SHAPE_ALT& shape : sizeAndShape->alt_shape )
777 shape = static_cast<ALTIUM_PAD_SHAPE_ALT>( aReader.Read<uint8_t>() );
778
779 for( uint8_t& radius : sizeAndShape->cornerradius )
780 radius = aReader.Read<uint8_t>();
781 }
782 else if( subrecord6 != 0 )
783 {
784 wxLogError( _( "Pads6 stream has unexpected length for subrecord 6: %d." ), subrecord6 );
785 }
786
787 aReader.SkipSubrecord();
788
789 if( aReader.HasParsingError() )
790 THROW_IO_ERROR( wxT( "Pads6 stream was not parsed correctly" ) );
791}
792
794{
795 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
796
797 if( recordtype != ALTIUM_RECORD::VIA )
798 THROW_IO_ERROR( wxT( "Vias6 stream has invalid recordtype" ) );
799
800 // Subrecord 1
801 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
802
803 aReader.Skip( 1 );
804
805 uint8_t flags1 = aReader.Read<uint8_t>();
806 is_test_fab_top = ( flags1 & 0x80 ) != 0;
807 is_tent_bottom = ( flags1 & 0x40 ) != 0;
808 is_tent_top = ( flags1 & 0x20 ) != 0;
809 is_locked = ( flags1 & 0x04 ) == 0;
810
811 uint8_t flags2 = aReader.Read<uint8_t>();
812 is_test_fab_bottom = ( flags2 & 0x01 ) != 0;
813
814 net = aReader.Read<uint16_t>();
815 aReader.Skip( 8 );
816 position = aReader.ReadVector2IPos();
817 diameter = aReader.ReadKicadUnit();
818 holesize = aReader.ReadKicadUnit();
819
820 layer_start = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
821 layer_end = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
822
823 if( subrecord1 <= 74 )
824 {
826 }
827 else
828 {
829 aReader.Skip( 43 );
830 viamode = static_cast<ALTIUM_PAD_MODE>( aReader.Read<uint8_t>() );
831 }
832
833 aReader.SkipSubrecord();
834
835 if( aReader.HasParsingError() )
836 THROW_IO_ERROR( wxT( "Vias6 stream was not parsed correctly" ) );
837}
838
840{
841 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
842
843 if( recordtype != ALTIUM_RECORD::TRACK )
844 THROW_IO_ERROR( wxT( "Tracks6 stream has invalid recordtype" ) );
845
846 // Subrecord 1
848
849 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
850
851 uint8_t flags1 = aReader.Read<uint8_t>();
852 is_locked = ( flags1 & 0x04 ) == 0;
853 is_polygonoutline = ( flags1 & 0x02 ) != 0;
854
855 uint8_t flags2 = aReader.Read<uint8_t>();
856 is_keepout = flags2 == 2;
857
858 net = aReader.Read<uint16_t>();
859 subpolyindex = aReader.Read<uint16_t>();
860 component = aReader.Read<uint16_t>();
861 aReader.Skip( 4 );
862 start = aReader.ReadVector2IPos();
863 end = aReader.ReadVector2IPos();
864 width = aReader.ReadKicadUnit();
865
866 if( aReader.GetRemainingSubrecordBytes() >= 13 )
867 {
868 aReader.Skip( 12 );
869 keepoutrestrictions = aReader.Read<uint8_t>();
870 }
871 else
872 {
873 keepoutrestrictions = is_keepout ? 0x1F : 0;
874 }
875
876 aReader.SkipSubrecord();
877
878 if( aReader.HasParsingError() )
879 THROW_IO_ERROR( wxT( "Tracks6 stream was not parsed correctly" ) );
880}
881
882ATEXT6::ATEXT6( ALTIUM_PARSER& aReader, std::map<uint32_t, wxString>& aStringTable )
883{
884 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
885
886 if( recordtype != ALTIUM_RECORD::TEXT )
887 THROW_IO_ERROR( wxT( "Texts6 stream has invalid recordtype" ) );
888
889 // Subrecord 1 - Properties
890 size_t subrecord1 = aReader.ReadAndSetSubrecordLength();
891
892 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
893 aReader.Skip( 6 );
894 component = aReader.Read<uint16_t>();
895 aReader.Skip( 4 );
896 position = aReader.ReadVector2IPos();
897 height = aReader.ReadKicadUnit();
898 aReader.Skip( 2 );
899 rotation = aReader.Read<double>();
900 isMirrored = aReader.Read<uint8_t>() != 0;
901 strokewidth = aReader.ReadKicadUnit();
902 isComment = aReader.Read<uint8_t>() != 0;
903 isDesignator = aReader.Read<uint8_t>() != 0;
904 aReader.Skip( 2 );
905 isBold = aReader.Read<uint8_t>() != 0;
906 isItalic = aReader.Read<uint8_t>() != 0;
907 aReader.Skip( 64 ); // font_name
908 isInverted = aReader.Read<uint8_t>() != 0;
909 aReader.Skip( 4 );
910 uint32_t stringIndex = aReader.Read<uint32_t>();
911 aReader.Skip( 13 );
912 textposition = static_cast<ALTIUM_TEXT_POSITION>( aReader.Read<uint8_t>() );
917 if( subrecord1 <= 230 )
919
920 aReader.Skip( 27 );
921 fonttype = static_cast<ALTIUM_TEXT_TYPE>( aReader.Read<uint8_t>() );
922
923 aReader.SkipSubrecord();
924
925 // Subrecord 2 - Legacy 8bit string, max 255 chars, unknown codepage
927
928 auto entry = aStringTable.find( stringIndex );
929
930 if( entry != aStringTable.end() )
931 text = entry->second;
932 else
933 text = aReader.ReadWxString();
934
935 // Normalize Windows line endings
936 text.Replace( wxT( "\r\n" ), wxT( "\n" ) );
937
938 aReader.SkipSubrecord();
939
940 if( aReader.HasParsingError() )
941 THROW_IO_ERROR( wxT( "Texts6 stream was not parsed correctly" ) );
942}
943
945{
946 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
947
948 if( recordtype != ALTIUM_RECORD::FILL )
949 THROW_IO_ERROR( wxT( "Fills6 stream has invalid recordtype" ) );
950
951 // Subrecord 1
953
954 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
955
956 uint8_t flags1 = aReader.Read<uint8_t>();
957 is_locked = ( flags1 & 0x04 ) == 0;
958
959 uint8_t flags2 = aReader.Read<uint8_t>();
960 is_keepout = flags2 == 2;
961
962 net = aReader.Read<uint16_t>();
963 aReader.Skip( 2 );
964 component = aReader.Read<uint16_t>();
965 aReader.Skip( 4 );
966 pos1 = aReader.ReadVector2IPos();
967 pos2 = aReader.ReadVector2IPos();
968 rotation = aReader.Read<double>();
969
970 if( aReader.GetRemainingSubrecordBytes() >= 10 )
971 {
972 aReader.Skip( 9 );
973 keepoutrestrictions = aReader.Read<uint8_t>();
974 }
975 else
976 {
977 keepoutrestrictions = is_keepout ? 0x1F : 0;
978 }
979
980 aReader.SkipSubrecord();
981
982 if( aReader.HasParsingError() )
983 THROW_IO_ERROR( wxT( "Fills6 stream was not parsed correctly" ) );
984}
985
986AREGION6::AREGION6( ALTIUM_PARSER& aReader, bool aExtendedVertices )
987{
988 ALTIUM_RECORD recordtype = static_cast<ALTIUM_RECORD>( aReader.Read<uint8_t>() );
989
990 if( recordtype != ALTIUM_RECORD::REGION )
991 THROW_IO_ERROR( wxT( "Regions6 stream has invalid recordtype" ) );
992
993 // Subrecord 1
995
996 layer = static_cast<ALTIUM_LAYER>( aReader.Read<uint8_t>() );
997
998 uint8_t flags1 = aReader.Read<uint8_t>();
999 is_locked = ( flags1 & 0x04 ) == 0;
1000
1001 uint8_t flags2 = aReader.Read<uint8_t>();
1002 is_keepout = flags2 == 2;
1003
1004 net = aReader.Read<uint16_t>();
1005 subpolyindex = aReader.Read<uint16_t>();
1006 component = aReader.Read<uint16_t>();
1007 aReader.Skip( 5 );
1008 holecount = aReader.Read<uint16_t>();
1009 aReader.Skip( 2 );
1010
1011 std::map<wxString, wxString> properties = aReader.ReadProperties();
1012
1013 if( properties.empty() )
1014 THROW_IO_ERROR( wxT( "Regions6 stream has empty properties" ) );
1015
1016 int pkind = ALTIUM_PARSER::ReadInt( properties, wxT( "KIND" ), 0 );
1017 bool is_cutout = ALTIUM_PARSER::ReadBool( properties, wxT( "ISBOARDCUTOUT" ), false );
1018
1019 is_shapebased = ALTIUM_PARSER::ReadBool( properties, wxT( "ISSHAPEBASED" ), false );
1020 keepoutrestrictions = static_cast<uint8_t>(
1021 ALTIUM_PARSER::ReadInt( properties, wxT( "KEEPOUTRESTRIC" ), 0x1F ) );
1022
1023 // TODO: this can differ from the other subpolyindex?!
1024 //subpolyindex = static_cast<uint16_t>(
1025 // ALTIUM_PARSER::ReadInt( properties, "SUBPOLYINDEX", ALTIUM_POLYGON_NONE ) );
1026
1027 switch( pkind )
1028 {
1029 case 0:
1030 if( is_cutout )
1031 {
1033 }
1034 else
1035 {
1037 }
1038 break;
1039 case 1:
1041 break;
1042 case 2:
1043 kind = ALTIUM_REGION_KIND::UNKNOWN_2; // TODO: what kind is this?
1044 break;
1045 case 3:
1046 kind = ALTIUM_REGION_KIND::UNKNOWN_3; // TODO: what kind is this?
1047 break;
1048 case 4:
1050 break;
1051 default:
1053 break;
1054 }
1055
1056 uint32_t num_outline_vertices = aReader.Read<uint32_t>();
1057
1058 for( uint32_t i = 0; i < num_outline_vertices; i++ )
1059 {
1060 if( aExtendedVertices )
1061 {
1062 bool isRound = aReader.Read<uint8_t>() != 0;
1063 VECTOR2I position = aReader.ReadVector2IPos();
1064 VECTOR2I center = aReader.ReadVector2IPos();
1065 int32_t radius = aReader.ReadKicadUnit();
1066 double angle1 = aReader.Read<double>();
1067 double angle2 = aReader.Read<double>();
1068 outline.emplace_back( isRound, radius, angle1, angle2, position, center );
1069 }
1070 else
1071 {
1072 // For some regions the coordinates are stored as double and not as int32_t
1073 int32_t x = ALTIUM_PARSER::ConvertToKicadUnit( aReader.Read<double>() );
1074 int32_t y = ALTIUM_PARSER::ConvertToKicadUnit( -aReader.Read<double>() );
1075 outline.emplace_back( VECTOR2I( x, y ) );
1076 }
1077 }
1078
1079 // TODO: for now we only support holes in regions where there are stored as double
1080 if( !aExtendedVertices )
1081 {
1082 holes.resize( holecount );
1083 for( uint16_t k = 0; k < holecount; k++ )
1084 {
1085 uint32_t num_hole_vertices = aReader.Read<uint32_t>();
1086 holes.at( k ).reserve( num_hole_vertices );
1087
1088 for( uint32_t i = 0; i < num_hole_vertices; i++ )
1089 {
1090 int32_t x = ALTIUM_PARSER::ConvertToKicadUnit( aReader.Read<double>() );
1091 int32_t y = ALTIUM_PARSER::ConvertToKicadUnit( -aReader.Read<double>() );
1092 holes.at( k ).emplace_back( VECTOR2I( x, y ) );
1093 }
1094 }
1095 }
1096
1097 aReader.SkipSubrecord();
1098
1099 if( aReader.HasParsingError() )
1100 THROW_IO_ERROR( wxT( "Regions6 stream was not parsed correctly" ) );
1101}
void altium_parse_polygons(std::map< wxString, wxString > &aProps, std::vector< ALTIUM_VERTICE > &aVertices)
ALTIUM_LAYER altium_layer_from_name(const wxString &aName)
static AEXTENDED_PRIMITIVE_INFORMATION_TYPE ReadAltiumExtendedPrimitiveInformationTypeFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
static ALTIUM_MODE ReadAltiumModeFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
static ALTIUM_RECORD ReadAltiumRecordFromProperties(const std::map< wxString, wxString > &aProps, wxString aKey)
ALTIUM_PAD_SHAPE_ALT
ALTIUM_TEXT_POSITION
ALTIUM_PAD_MODE
ALTIUM_TEXT_TYPE
ALTIUM_PAD_SHAPE
ALTIUM_DIMENSION_KIND
ALTIUM_PAD_HOLE_SHAPE
const uint16_t ALTIUM_NET_UNCONNECTED
ALTIUM_CLASS_KIND
ALTIUM_MODE
ALTIUM_LAYER
AEXTENDED_PRIMITIVE_INFORMATION_TYPE
ALTIUM_RECORD
wxString ReadWxString()
static int ReadInt(const std::map< wxString, wxString > &aProps, const wxString &aKey, int aDefault)
int32_t ReadKicadUnitX()
bool HasParsingError()
std::map< wxString, wxString > ReadProperties()
size_t GetRemainingSubrecordBytes() const
static wxString ReadString(const std::map< wxString, wxString > &aProps, const wxString &aKey, const wxString &aDefault)
size_t ReadAndSetSubrecordLength()
int32_t ReadKicadUnitY()
static double ReadDouble(const std::map< wxString, wxString > &aProps, const wxString &aKey, double aDefault)
VECTOR2I ReadVector2ISize()
static int32_t ConvertToKicadUnit(const double aValue)
int32_t ReadKicadUnit()
static bool ReadBool(const std::map< wxString, wxString > &aProps, const wxString &aKey, bool aDefault)
VECTOR2I ReadVector2IPos()
void Skip(size_t aLength)
void SkipSubrecord()
T y
Definition: vector3.h:62
T z
Definition: vector3.h:63
T x
Definition: vector3.h:61
#define _(s)
#define THROW_IO_ERROR(msg)
Definition: ki_exception.h:38
double startangle
uint16_t component
bool is_keepout
uint32_t width
AARC6(ALTIUM_PARSER &aReader)
ALTIUM_LAYER layer
uint8_t keepoutrestrictions
VECTOR2I center
uint32_t radius
uint16_t net
bool is_locked
bool is_polygonoutline
double endangle
uint16_t subpolyindex
ABOARD6(ALTIUM_PARSER &aReader)
VECTOR2I sheetpos
wxSize sheetsize
std::vector< ABOARD6_LAYER_STACKUP > stackup
std::vector< ALTIUM_VERTICE > board_vertices
wxString uniqueid
std::vector< wxString > names
ALTIUM_CLASS_KIND kind
wxString name
ACLASS6(ALTIUM_PARSER &aReader)
ALTIUM_TEXT_POSITION commentautoposition
ALTIUM_TEXT_POSITION nameautoposition
ACOMPONENT6(ALTIUM_PARSER &aReader)
wxString sourcefootprintlibrary
ALTIUM_LAYER layer
wxString sourcelibreference
wxString sourcedesignator
wxString sourcecomponentlibrary
ACOMPONENTBODY6(ALTIUM_PARSER &aReader)
int32_t textprecision
ALTIUM_UNIT textunit
wxString textsuffix
ADIMENSION6(ALTIUM_PARSER &aReader)
uint32_t textlinewidth
wxString textformat
ALTIUM_LAYER layer
std::vector< VECTOR2I > textPoint
wxString textprefix
uint32_t linewidth
ALTIUM_DIMENSION_KIND kind
uint32_t textheight
std::vector< VECTOR2I > referencePoint
AEXTENDED_PRIMITIVE_INFORMATION_TYPE type
AEXTENDED_PRIMITIVE_INFORMATION(ALTIUM_PARSER &aReader)
VECTOR2I pos2
ALTIUM_LAYER layer
uint16_t net
VECTOR2I pos1
double rotation
uint8_t keepoutrestrictions
uint16_t component
AFILL6(ALTIUM_PARSER &aReader)
wxString name
VECTOR3D rotation
AMODEL(ALTIUM_PARSER &aReader)
ANET6(ALTIUM_PARSER &aReader)
wxString name
double holerotation
int32_t soldermaskexpansionmanual
uint16_t net
ALTIUM_LAYER layer
std::unique_ptr< APAD6_SIZE_AND_SHAPE > sizeAndShape
ALTIUM_LAYER tolayer
ALTIUM_PAD_SHAPE topshape
ALTIUM_PAD_MODE padmode
ALTIUM_MODE pastemaskexpansionmode
uint32_t holesize
double direction
ALTIUM_MODE soldermaskexpansionmode
wxString name
bool is_test_fab_bottom
bool is_tent_bottom
VECTOR2I botsize
ALTIUM_PAD_SHAPE botshape
uint16_t component
VECTOR2I midsize
ALTIUM_PAD_SHAPE midshape
int32_t pastemaskexpansionmanual
bool is_tent_top
APAD6(ALTIUM_PARSER &aReader)
ALTIUM_LAYER fromlayer
VECTOR2I position
bool is_locked
VECTOR2I topsize
bool is_test_fab_top
APOLYGON6(ALTIUM_PARSER &aReader)
int32_t minprimlength
std::vector< ALTIUM_VERTICE > vertices
ALTIUM_POLYGON_HATCHSTYLE hatchstyle
int32_t pourindex
int32_t trackwidth
ALTIUM_LAYER layer
int32_t gridsize
uint8_t keepoutrestrictions
ALTIUM_LAYER layer
AREGION6(ALTIUM_PARSER &aReader, bool aExtendedVertices)
uint16_t holecount
std::vector< ALTIUM_VERTICE > outline
uint16_t subpolyindex
std::vector< std::vector< ALTIUM_VERTICE > > holes
uint16_t component
uint16_t net
ALTIUM_REGION_KIND kind
ALTIUM_RULE_KIND kind
ALTIUM_CONNECT_STYLE polygonconnectStyle
wxString scope1expr
wxString name
int planeclearanceClearance
int32_t polygonconnectReliefconductorwidth
wxString scope2expr
ARULE6(ALTIUM_PARSER &aReader)
int32_t polygonconnectAirgapwidth
int polygonconnectReliefentries
ALTIUM_TEXT_POSITION textposition
uint16_t component
wxString text
double rotation
ATEXT6(ALTIUM_PARSER &aReader, std::map< uint32_t, wxString > &aStringTable)
uint32_t height
ALTIUM_LAYER layer
VECTOR2I position
ALTIUM_TEXT_TYPE fonttype
bool isDesignator
uint32_t strokewidth
VECTOR2I end
uint32_t width
bool is_polygonoutline
uint16_t net
uint16_t subpolyindex
uint8_t keepoutrestrictions
ATRACK6(ALTIUM_PARSER &aReader)
VECTOR2I start
ALTIUM_LAYER layer
uint16_t component
uint32_t diameter
uint16_t net
VECTOR2I position
bool is_locked
bool is_tent_top
bool is_test_fab_top
bool is_tent_bottom
bool is_test_fab_bottom
AVIA6(ALTIUM_PARSER &aReader)
ALTIUM_PAD_MODE viamode
ALTIUM_LAYER layer_start
ALTIUM_LAYER layer_end
uint32_t holesize
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590