1 /*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2020 Thomas Pointhuber <thomas.pointhuber@gmx.at>
5 * Copyright (C) 2021 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 <memory>
26
27 #include "altium_parser_sch.h"
28 #include <plugins/altium/altium_parser.h>
29 #include <plugins/altium/altium_parser_utils.h>
30 #include <sch_plugins/altium/sch_altium_plugin.h>
31
32 #include <schematic.h>
33
34 #include <lib_shape.h>
35 #include <lib_id.h>
36 #include <lib_item.h>
37 #include <lib_pin.h>
38 #include <lib_text.h>
39
40 #include <sch_bitmap.h>
41 #include <sch_bus_entry.h>
42 #include <sch_symbol.h>
43 #include <sch_junction.h>
44 #include <sch_line.h>
45 #include <sch_no_connect.h>
46 #include <sch_screen.h>
47 #include <sch_sheet.h>
48 #include <sch_sheet_pin.h>
49 #include <sch_text.h>
50
51 #include <bezier_curves.h>
52 #include <compoundfilereader.h>
53 #include <string_utils.h>
54 #include <sch_edit_frame.h>
55 #include <trigo.h>
56 #include <wildcards_and_files_ext.h>
57 #include <wx/mstream.h>
58 #include <wx/log.h>
59 #include <wx/zstream.h>
60 #include <wx/wfstream.h>
61 #include <trigo.h>
62
GetRelativePosition(const wxPoint & aPosition,const SCH_SYMBOL * aSymbol)63 const wxPoint GetRelativePosition( const wxPoint& aPosition, const SCH_SYMBOL* aSymbol )
64 {
65 TRANSFORM t = aSymbol->GetTransform().InverseTransform();
66 return t.TransformCoordinate( aPosition - aSymbol->GetPosition() );
67 }
68
69
GetColorFromInt(int color)70 COLOR4D GetColorFromInt( int color )
71 {
72 int red = color & 0x0000FF;
73 int green = ( color & 0x00FF00 ) >> 8;
74 int blue = ( color & 0xFF0000 ) >> 16;
75
76 return COLOR4D().FromCSSRGBA( red, green, blue, 1.0 );
77 }
78
SCH_ALTIUM_PLUGIN()79 SCH_ALTIUM_PLUGIN::SCH_ALTIUM_PLUGIN()
80 {
81 m_rootSheet = nullptr;
82 m_currentSheet = nullptr;
83 m_schematic = nullptr;
84
85 m_reporter = &WXLOG_REPORTER::GetInstance();
86 }
87
88
~SCH_ALTIUM_PLUGIN()89 SCH_ALTIUM_PLUGIN::~SCH_ALTIUM_PLUGIN()
90 {
91 }
92
93
GetName() const94 const wxString SCH_ALTIUM_PLUGIN::GetName() const
95 {
96 return "Altium";
97 }
98
99
GetFileExtension() const100 const wxString SCH_ALTIUM_PLUGIN::GetFileExtension() const
101 {
102 return "SchDoc";
103 }
104
105
GetLibraryFileExtension() const106 const wxString SCH_ALTIUM_PLUGIN::GetLibraryFileExtension() const
107 {
108 return "SchLib";
109 }
110
111
GetModifyHash() const112 int SCH_ALTIUM_PLUGIN::GetModifyHash() const
113 {
114 return 0;
115 }
116
117
CheckHeader(const wxString & aFileName)118 bool SCH_ALTIUM_PLUGIN::CheckHeader( const wxString& aFileName )
119 {
120 // TODO
121
122 return true;
123 }
124
125
getLibName()126 wxString SCH_ALTIUM_PLUGIN::getLibName()
127 {
128 if( m_libName.IsEmpty() )
129 {
130 // Try to come up with a meaningful name
131 m_libName = m_schematic->Prj().GetProjectName();
132
133 if( m_libName.IsEmpty() )
134 {
135 wxFileName fn( m_rootSheet->GetFileName() );
136 m_libName = fn.GetName();
137 }
138
139 if( m_libName.IsEmpty() )
140 m_libName = "noname";
141
142 m_libName += "-altium-import";
143 m_libName = LIB_ID::FixIllegalChars( m_libName, true );
144 }
145
146 return m_libName;
147 }
148
149
getLibFileName()150 wxFileName SCH_ALTIUM_PLUGIN::getLibFileName()
151 {
152 wxFileName fn( m_schematic->Prj().GetProjectPath(), getLibName(), KiCadSymbolLibFileExtension );
153
154 return fn;
155 }
156
157
Load(const wxString & aFileName,SCHEMATIC * aSchematic,SCH_SHEET * aAppendToMe,const PROPERTIES * aProperties)158 SCH_SHEET* SCH_ALTIUM_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
159 SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties )
160 {
161 wxASSERT( !aFileName || aSchematic != nullptr );
162
163 wxFileName fileName( aFileName );
164 fileName.SetExt( KiCadSchematicFileExtension );
165 m_schematic = aSchematic;
166
167 // Delete on exception, if I own m_rootSheet, according to aAppendToMe
168 std::unique_ptr<SCH_SHEET> deleter( aAppendToMe ? nullptr : m_rootSheet );
169
170 if( aAppendToMe )
171 {
172 wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
173 m_rootSheet = &aSchematic->Root();
174 }
175 else
176 {
177 m_rootSheet = new SCH_SHEET( aSchematic );
178 m_rootSheet->SetFileName( fileName.GetFullPath() );
179
180 aSchematic->SetRoot( m_rootSheet );
181
182 SCH_SHEET_PATH sheetpath;
183 sheetpath.push_back( m_rootSheet );
184
185 m_rootSheet->AddInstance( sheetpath );
186 m_rootSheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a
187 // pageNumber record for it
188 }
189
190 if( !m_rootSheet->GetScreen() )
191 {
192 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
193 screen->SetFileName( aFileName );
194 m_rootSheet->SetScreen( screen );
195 }
196
197 SYMBOL_LIB_TABLE* libTable = m_schematic->Prj().SchSymbolLibTable();
198
199 wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." );
200
201 m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
202
203 /// @note No check is being done here to see if the existing symbol library exists so this
204 /// will overwrite the existing one.
205 if( !libTable->HasLibrary( getLibName() ) )
206 {
207 // Create a new empty symbol library.
208 m_pi->CreateSymbolLib( getLibFileName().GetFullPath() );
209 wxString libTableUri = "${KIPRJMOD}/" + getLibFileName().GetFullName();
210
211 // Add the new library to the project symbol library table.
212 libTable->InsertRow( new SYMBOL_LIB_TABLE_ROW( getLibName(), libTableUri,
213 wxString( "KiCad" ) ) );
214
215 // Save project symbol library table.
216 wxFileName fn( m_schematic->Prj().GetProjectPath(),
217 SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
218
219 // So output formatter goes out of scope and closes the file before reloading.
220 {
221 FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
222 libTable->Format( &formatter, 0 );
223 }
224
225 // Reload the symbol library table.
226 m_schematic->Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, nullptr );
227 m_schematic->Prj().SchSymbolLibTable();
228 }
229
230 m_currentSheet = m_rootSheet;
231 ParseAltiumSch( aFileName );
232
233 m_pi->SaveLibrary( getLibFileName().GetFullPath() );
234
235 SCH_SCREENS allSheets( m_rootSheet );
236 allSheets.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
237 allSheets.ClearEditFlags();
238
239 return m_rootSheet;
240 }
241
242
ParseAltiumSch(const wxString & aFileName)243 void SCH_ALTIUM_PLUGIN::ParseAltiumSch( const wxString& aFileName )
244 {
245 // Open file
246 FILE* fp = wxFopen( aFileName, "rb" );
247
248 if( fp == nullptr )
249 {
250 m_reporter->Report( wxString::Format( _( "Cannot open file '%s'." ), aFileName ),
251 RPT_SEVERITY_ERROR );
252 return;
253 }
254
255 fseek( fp, 0, SEEK_END );
256 long len = ftell( fp );
257
258 if( len < 0 )
259 {
260 fclose( fp );
261 THROW_IO_ERROR( "Read error, cannot determine length of file." );
262 }
263
264 std::unique_ptr<unsigned char[]> buffer( new unsigned char[len] );
265 fseek( fp, 0, SEEK_SET );
266
267 size_t bytesRead = fread( buffer.get(), sizeof( unsigned char ), len, fp );
268 fclose( fp );
269
270 if( static_cast<size_t>( len ) != bytesRead )
271 THROW_IO_ERROR( "Read error." );
272
273 try
274 {
275 CFB::CompoundFileReader reader( buffer.get(), bytesRead );
276 ParseStorage( reader ); // we need this before parsing the FileHeader
277 ParseFileHeader( reader );
278 }
279 catch( CFB::CFBException& exception )
280 {
281 THROW_IO_ERROR( exception.what() );
282 }
283 }
284
285
ParseStorage(const CFB::CompoundFileReader & aReader)286 void SCH_ALTIUM_PLUGIN::ParseStorage( const CFB::CompoundFileReader& aReader )
287 {
288 const CFB::COMPOUND_FILE_ENTRY* file = FindStream( aReader, "Storage" );
289
290 if( file == nullptr )
291 return;
292
293 ALTIUM_PARSER reader( aReader, file );
294
295 std::map<wxString, wxString> properties = reader.ReadProperties();
296 wxString header = ALTIUM_PARSER::ReadString( properties, "HEADER", "" );
297 int weight = ALTIUM_PARSER::ReadInt( properties, "WEIGHT", 0 );
298
299 if( weight < 0 )
300 THROW_IO_ERROR( "Storage weight is negative!" );
301
302 for( int i = 0; i < weight; i++ )
303 {
304 m_altiumStorage.emplace_back( reader );
305 }
306
307 if( reader.HasParsingError() )
308 THROW_IO_ERROR( "stream was not parsed correctly!" );
309
310 // TODO pointhi: is it possible to have multiple headers in one Storage file? Otherwise
311 // throw IO Error.
312 if( reader.GetRemainingBytes() != 0 )
313 {
314 m_reporter->Report( wxString::Format( _( "Storage file not fully parsed "
315 "(%d bytes remaining)." ),
316 reader.GetRemainingBytes() ),
317 RPT_SEVERITY_ERROR );
318 }
319 }
320
321
ParseFileHeader(const CFB::CompoundFileReader & aReader)322 void SCH_ALTIUM_PLUGIN::ParseFileHeader( const CFB::CompoundFileReader& aReader )
323 {
324 const CFB::COMPOUND_FILE_ENTRY* file = FindStream( aReader, "FileHeader" );
325
326 if( file == nullptr )
327 THROW_IO_ERROR( "FileHeader not found" );
328
329 ALTIUM_PARSER reader( aReader, file );
330
331 if( reader.GetRemainingBytes() <= 0 )
332 {
333 THROW_IO_ERROR( "FileHeader does not contain any data" );
334 }
335 else
336 {
337 std::map<wxString, wxString> properties = reader.ReadProperties();
338
339 int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
340 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
341
342 if( record != ALTIUM_SCH_RECORD::HEADER )
343 THROW_IO_ERROR( "Header expected" );
344 }
345
346 // Prepare some local variables
347 wxASSERT( m_altiumPortsCurrentSheet.empty() );
348 wxASSERT( !m_currentTitleBlock );
349
350 m_currentTitleBlock = std::make_unique<TITLE_BLOCK>();
351
352 // index is required to resolve OWNERINDEX
353 for( int index = 0; reader.GetRemainingBytes() > 0; index++ )
354 {
355 std::map<wxString, wxString> properties = reader.ReadProperties();
356
357 int recordId = ALTIUM_PARSER::ReadInt( properties, "RECORD", 0 );
358 ALTIUM_SCH_RECORD record = static_cast<ALTIUM_SCH_RECORD>( recordId );
359
360 // see: https://github.com/vadmium/python-altium/blob/master/format.md
361 switch( record )
362 {
363 case ALTIUM_SCH_RECORD::HEADER:
364 THROW_IO_ERROR( "Header already parsed" );
365 case ALTIUM_SCH_RECORD::COMPONENT:
366 ParseComponent( index, properties );
367 break;
368 case ALTIUM_SCH_RECORD::PIN:
369 ParsePin( properties );
370 break;
371 case ALTIUM_SCH_RECORD::IEEE_SYMBOL:
372 break;
373 case ALTIUM_SCH_RECORD::LABEL:
374 ParseLabel( properties );
375 break;
376 case ALTIUM_SCH_RECORD::BEZIER:
377 ParseBezier( properties );
378 break;
379 case ALTIUM_SCH_RECORD::POLYLINE:
380 ParsePolyline( properties );
381 break;
382 case ALTIUM_SCH_RECORD::POLYGON:
383 ParsePolygon( properties );
384 break;
385 case ALTIUM_SCH_RECORD::ELLIPSE:
386 break;
387 case ALTIUM_SCH_RECORD::PIECHART:
388 break;
389 case ALTIUM_SCH_RECORD::ROUND_RECTANGLE:
390 ParseRoundRectangle( properties );
391 break;
392 case ALTIUM_SCH_RECORD::ELLIPTICAL_ARC:
393 break;
394 case ALTIUM_SCH_RECORD::ARC:
395 ParseArc( properties );
396 break;
397 case ALTIUM_SCH_RECORD::LINE:
398 ParseLine( properties );
399 break;
400 case ALTIUM_SCH_RECORD::RECTANGLE:
401 ParseRectangle( properties );
402 break;
403 case ALTIUM_SCH_RECORD::SHEET_SYMBOL:
404 ParseSheetSymbol( index, properties );
405 break;
406 case ALTIUM_SCH_RECORD::SHEET_ENTRY:
407 ParseSheetEntry( properties );
408 break;
409 case ALTIUM_SCH_RECORD::POWER_PORT:
410 ParsePowerPort( properties );
411 break;
412 case ALTIUM_SCH_RECORD::PORT:
413 // Ports are parsed after the sheet was parsed
414 // This is required because we need all electrical connection points before placing.
415 m_altiumPortsCurrentSheet.emplace_back( properties );
416 break;
417 case ALTIUM_SCH_RECORD::NO_ERC:
418 ParseNoERC( properties );
419 break;
420 case ALTIUM_SCH_RECORD::NET_LABEL:
421 ParseNetLabel( properties );
422 break;
423 case ALTIUM_SCH_RECORD::BUS:
424 ParseBus( properties );
425 break;
426 case ALTIUM_SCH_RECORD::WIRE:
427 ParseWire( properties );
428 break;
429 case ALTIUM_SCH_RECORD::TEXT_FRAME:
430 ParseTextFrame( properties );
431 break;
432 case ALTIUM_SCH_RECORD::JUNCTION:
433 ParseJunction( properties );
434 break;
435 case ALTIUM_SCH_RECORD::IMAGE:
436 ParseImage( properties );
437 break;
438 case ALTIUM_SCH_RECORD::SHEET:
439 ParseSheet( properties );
440 break;
441 case ALTIUM_SCH_RECORD::SHEET_NAME:
442 ParseSheetName( properties );
443 break;
444 case ALTIUM_SCH_RECORD::FILE_NAME:
445 ParseFileName( properties );
446 break;
447 case ALTIUM_SCH_RECORD::DESIGNATOR:
448 ParseDesignator( properties );
449 break;
450 case ALTIUM_SCH_RECORD::BUS_ENTRY:
451 ParseBusEntry( properties );
452 break;
453 case ALTIUM_SCH_RECORD::TEMPLATE:
454 break;
455 case ALTIUM_SCH_RECORD::PARAMETER:
456 ParseParameter( properties );
457 break;
458 case ALTIUM_SCH_RECORD::WARNING_SIGN:
459 break;
460 case ALTIUM_SCH_RECORD::IMPLEMENTATION_LIST:
461 ParseImplementationList( index, properties );
462 break;
463 case ALTIUM_SCH_RECORD::IMPLEMENTATION:
464 ParseImplementation( properties );
465 break;
466 case ALTIUM_SCH_RECORD::RECORD_46:
467 break;
468 case ALTIUM_SCH_RECORD::RECORD_47:
469 break;
470 case ALTIUM_SCH_RECORD::RECORD_48:
471 break;
472 case ALTIUM_SCH_RECORD::NOTE:
473 ParseNote( properties );
474 break;
475 case ALTIUM_SCH_RECORD::COMPILE_MASK:
476 m_reporter->Report( _( "Compile mask not currently supported." ), RPT_SEVERITY_ERROR );
477 break;
478 case ALTIUM_SCH_RECORD::RECORD_215:
479 break;
480 case ALTIUM_SCH_RECORD::RECORD_216:
481 break;
482 case ALTIUM_SCH_RECORD::RECORD_217:
483 break;
484 case ALTIUM_SCH_RECORD::RECORD_218:
485 break;
486 case ALTIUM_SCH_RECORD::RECORD_226:
487 break;
488 default:
489 m_reporter->Report( wxString::Format( _( "Unknown Record id: %d." ), recordId ),
490 RPT_SEVERITY_ERROR );
491 break;
492 }
493 }
494
495 if( reader.HasParsingError() )
496 THROW_IO_ERROR( "stream was not parsed correctly!" );
497
498 if( reader.GetRemainingBytes() != 0 )
499 THROW_IO_ERROR( "stream is not fully parsed" );
500
501 // assign LIB_SYMBOL -> COMPONENT
502 for( std::pair<const int, SCH_SYMBOL*>& symbol : m_symbols )
503 {
504 auto libSymbolIt = m_libSymbols.find( symbol.first );
505
506 if( libSymbolIt == m_libSymbols.end() )
507 THROW_IO_ERROR( "every symbol should have a symbol attached" );
508
509 m_pi->SaveSymbol( getLibFileName().GetFullPath(),
510 new LIB_SYMBOL( *( libSymbolIt->second ) ), m_properties.get() );
511
512 symbol.second->SetLibSymbol( libSymbolIt->second );
513 }
514
515 // Handle title blocks
516 m_currentSheet->GetScreen()->SetTitleBlock( *m_currentTitleBlock );
517 m_currentTitleBlock.reset();
518
519 // Handle Ports
520 for( const ASCH_PORT& port : m_altiumPortsCurrentSheet )
521 ParsePort( port );
522
523 m_altiumPortsCurrentSheet.clear();
524
525 m_symbols.clear();
526 m_libSymbols.clear();
527
528 // Otherwise we cannot save the imported sheet?
529 m_currentSheet->SetModified();
530 }
531
532
IsComponentPartVisible(int aOwnerindex,int aOwnerpartdisplaymode) const533 bool SCH_ALTIUM_PLUGIN::IsComponentPartVisible( int aOwnerindex, int aOwnerpartdisplaymode ) const
534 {
535 const auto& component = m_altiumComponents.find( aOwnerindex );
536
537 if( component == m_altiumComponents.end() )
538 return false;
539
540 return component->second.displaymode == aOwnerpartdisplaymode;
541 }
542
543
GetFileFromStorage(const wxString & aFilename) const544 const ASCH_STORAGE_FILE* SCH_ALTIUM_PLUGIN::GetFileFromStorage( const wxString& aFilename ) const
545 {
546 const ASCH_STORAGE_FILE* nonExactMatch = nullptr;
547
548 for( const ASCH_STORAGE_FILE& file : m_altiumStorage )
549 {
550 if( file.filename.IsSameAs( aFilename ) )
551 return &file;
552
553 if( file.filename.EndsWith( aFilename ) )
554 nonExactMatch = &file;
555 }
556
557 return nonExactMatch;
558 }
559
560
ParseComponent(int aIndex,const std::map<wxString,wxString> & aProperties)561 void SCH_ALTIUM_PLUGIN::ParseComponent( int aIndex,
562 const std::map<wxString, wxString>& aProperties )
563 {
564 auto pair = m_altiumComponents.insert( { aIndex, ASCH_SYMBOL( aProperties ) } );
565 const ASCH_SYMBOL& elem = pair.first->second;
566
567 // TODO: this is a hack until we correctly apply all transformations to every element
568 wxString name = wxString::Format( "%d%s_%s",
569 elem.orientation,
570 elem.isMirrored ? "_mirrored" : "",
571 elem.libreference );
572 LIB_ID libId = AltiumToKiCadLibID( getLibName(), name );
573
574 LIB_SYMBOL* ksymbol = new LIB_SYMBOL( wxEmptyString );
575 ksymbol->SetName( name );
576 ksymbol->SetDescription( elem.componentdescription );
577 ksymbol->SetLibId( libId );
578 m_libSymbols.insert( { aIndex, ksymbol } );
579
580 // each component has its own symbol for now
581 SCH_SYMBOL* symbol = new SCH_SYMBOL();
582
583 symbol->SetPosition( elem.location + m_sheetOffset );
584
585 // TODO: keep it simple for now, and only set position.
586 //component->SetOrientation( elem.orientation );
587 symbol->SetLibId( libId );
588
589 symbol->SetUnit( elem.currentpartid );
590
591 m_currentSheet->GetScreen()->Append( symbol );
592
593 m_symbols.insert( { aIndex, symbol } );
594 }
595
596
ParsePin(const std::map<wxString,wxString> & aProperties)597 void SCH_ALTIUM_PLUGIN::ParsePin( const std::map<wxString, wxString>& aProperties )
598 {
599 ASCH_PIN elem( aProperties );
600
601 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
602
603 if( libSymbolIt == m_libSymbols.end() )
604 {
605 // TODO: e.g. can depend on Template (RECORD=39
606 m_reporter->Report( wxString::Format( _( "Pin's owner (%d) not found." ), elem.ownerindex ),
607 RPT_SEVERITY_ERROR );
608 return;
609 }
610
611 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
612 return;
613
614 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
615 LIB_PIN* pin = new LIB_PIN( libSymbolIt->second );
616 libSymbolIt->second->AddDrawItem( pin );
617
618 pin->SetUnit( elem.ownerpartid );
619
620 pin->SetName( elem.name );
621 pin->SetNumber( elem.designator );
622 pin->SetLength( elem.pinlength );
623
624 if( !elem.showDesignator )
625 pin->SetNumberTextSize( 0 );
626
627 if( !elem.showPinName )
628 pin->SetNameTextSize( 0 );
629
630 wxPoint pinLocation = elem.location; // the location given is not the connection point!
631
632 switch( elem.orientation )
633 {
634 case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
635 pin->SetOrientation( DrawPinOrient::PIN_LEFT );
636 pinLocation.x += elem.pinlength;
637 break;
638 case ASCH_RECORD_ORIENTATION::UPWARDS:
639 pin->SetOrientation( DrawPinOrient::PIN_DOWN );
640 pinLocation.y -= elem.pinlength;
641 break;
642 case ASCH_RECORD_ORIENTATION::LEFTWARDS:
643 pin->SetOrientation( DrawPinOrient::PIN_RIGHT );
644 pinLocation.x -= elem.pinlength;
645 break;
646 case ASCH_RECORD_ORIENTATION::DOWNWARDS:
647 pin->SetOrientation( DrawPinOrient::PIN_UP );
648 pinLocation.y += elem.pinlength;
649 break;
650 default:
651 m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
652 break;
653 }
654
655 // TODO: position can be sometimes off a little bit!
656 pin->SetPosition( GetRelativePosition( pinLocation + m_sheetOffset, symbol ) );
657
658 // TODO: the following fix is even worse for now?
659 // pin->SetPosition( GetRelativePosition( elem.kicadLocation, symbol ) );
660
661 switch( elem.electrical )
662 {
663 case ASCH_PIN_ELECTRICAL::INPUT:
664 pin->SetType( ELECTRICAL_PINTYPE::PT_INPUT );
665 break;
666 case ASCH_PIN_ELECTRICAL::BIDI:
667 pin->SetType( ELECTRICAL_PINTYPE::PT_BIDI );
668 break;
669 case ASCH_PIN_ELECTRICAL::OUTPUT:
670 pin->SetType( ELECTRICAL_PINTYPE::PT_OUTPUT );
671 break;
672 case ASCH_PIN_ELECTRICAL::OPEN_COLLECTOR:
673 pin->SetType( ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR );
674 break;
675 case ASCH_PIN_ELECTRICAL::PASSIVE:
676 pin->SetType( ELECTRICAL_PINTYPE::PT_PASSIVE );
677 break;
678 case ASCH_PIN_ELECTRICAL::TRISTATE:
679 pin->SetType( ELECTRICAL_PINTYPE::PT_TRISTATE );
680 break;
681 case ASCH_PIN_ELECTRICAL::OPEN_EMITTER:
682 pin->SetType( ELECTRICAL_PINTYPE::PT_OPENEMITTER );
683 break;
684 case ASCH_PIN_ELECTRICAL::POWER:
685 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
686 break;
687 case ASCH_PIN_ELECTRICAL::UNKNOWN:
688 default:
689 pin->SetType( ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
690 m_reporter->Report( _( "Pin has unexpected electrical type." ), RPT_SEVERITY_WARNING );
691 break;
692 }
693
694 if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::UNKNOWN )
695 m_reporter->Report( _( "Pin has unexpected outer edge type." ), RPT_SEVERITY_WARNING );
696
697 if( elem.symbolInnerEdge == ASCH_PIN_SYMBOL_INNEREDGE::UNKNOWN )
698 m_reporter->Report( _( "Pin has unexpected inner edge type." ), RPT_SEVERITY_WARNING );
699
700 if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::NEGATED )
701 {
702 switch( elem.symbolInnerEdge )
703 {
704 case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
705 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED_CLOCK );
706 break;
707 default:
708 pin->SetShape( GRAPHIC_PINSHAPE::INVERTED );
709 break;
710 }
711 }
712 else if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::LOW_INPUT )
713 {
714 switch( elem.symbolInnerEdge )
715 {
716 case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
717 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK_LOW );
718 break;
719 default:
720 pin->SetShape( GRAPHIC_PINSHAPE::INPUT_LOW );
721 break;
722 }
723 }
724 else if( elem.symbolOuterEdge == ASCH_PIN_SYMBOL_OUTEREDGE::LOW_OUTPUT )
725 {
726 pin->SetShape( GRAPHIC_PINSHAPE::OUTPUT_LOW );
727 }
728 else
729 {
730 switch( elem.symbolInnerEdge )
731 {
732 case ASCH_PIN_SYMBOL_INNEREDGE::CLOCK:
733 pin->SetShape( GRAPHIC_PINSHAPE::CLOCK );
734 break;
735 default:
736 pin->SetShape( GRAPHIC_PINSHAPE::LINE ); // nothing to do
737 break;
738 }
739 }
740 }
741
742
SetTextPositioning(EDA_TEXT * text,ASCH_LABEL_JUSTIFICATION justification,ASCH_RECORD_ORIENTATION orientation)743 void SetTextPositioning( EDA_TEXT* text, ASCH_LABEL_JUSTIFICATION justification,
744 ASCH_RECORD_ORIENTATION orientation )
745 {
746 int vjustify, hjustify;
747 double angle = TEXT_ANGLE_HORIZ;
748
749 switch( justification )
750 {
751 default:
752 case ASCH_LABEL_JUSTIFICATION::UNKNOWN:
753 case ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT:
754 case ASCH_LABEL_JUSTIFICATION::BOTTOM_CENTER:
755 case ASCH_LABEL_JUSTIFICATION::BOTTOM_RIGHT:
756 vjustify = EDA_TEXT_VJUSTIFY_T::GR_TEXT_VJUSTIFY_BOTTOM;
757 break;
758 case ASCH_LABEL_JUSTIFICATION::CENTER_LEFT:
759 case ASCH_LABEL_JUSTIFICATION::CENTER_CENTER:
760 case ASCH_LABEL_JUSTIFICATION::CENTER_RIGHT:
761 vjustify = EDA_TEXT_VJUSTIFY_T::GR_TEXT_VJUSTIFY_CENTER;
762 break;
763 case ASCH_LABEL_JUSTIFICATION::TOP_LEFT:
764 case ASCH_LABEL_JUSTIFICATION::TOP_CENTER:
765 case ASCH_LABEL_JUSTIFICATION::TOP_RIGHT:
766 vjustify = EDA_TEXT_VJUSTIFY_T::GR_TEXT_VJUSTIFY_TOP;
767 break;
768 }
769
770 switch( justification )
771 {
772 default:
773 case ASCH_LABEL_JUSTIFICATION::UNKNOWN:
774 case ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT:
775 case ASCH_LABEL_JUSTIFICATION::CENTER_LEFT:
776 case ASCH_LABEL_JUSTIFICATION::TOP_LEFT:
777 hjustify = EDA_TEXT_HJUSTIFY_T::GR_TEXT_HJUSTIFY_LEFT;
778 break;
779 case ASCH_LABEL_JUSTIFICATION::BOTTOM_CENTER:
780 case ASCH_LABEL_JUSTIFICATION::CENTER_CENTER:
781 case ASCH_LABEL_JUSTIFICATION::TOP_CENTER:
782 hjustify = EDA_TEXT_HJUSTIFY_T::GR_TEXT_HJUSTIFY_CENTER;
783 break;
784 case ASCH_LABEL_JUSTIFICATION::BOTTOM_RIGHT:
785 case ASCH_LABEL_JUSTIFICATION::CENTER_RIGHT:
786 case ASCH_LABEL_JUSTIFICATION::TOP_RIGHT:
787 hjustify = EDA_TEXT_HJUSTIFY_T::GR_TEXT_HJUSTIFY_RIGHT;
788 break;
789 }
790
791 switch( orientation )
792 {
793 case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
794 angle = TEXT_ANGLE_HORIZ;
795 break;
796 case ASCH_RECORD_ORIENTATION::LEFTWARDS:
797 vjustify *= -1;
798 hjustify *= -1;
799 angle = TEXT_ANGLE_HORIZ;
800 break;
801 case ASCH_RECORD_ORIENTATION::UPWARDS:
802 angle = TEXT_ANGLE_VERT;
803 break;
804 case ASCH_RECORD_ORIENTATION::DOWNWARDS:
805 vjustify *= -1;
806 hjustify *= -1;
807 angle = TEXT_ANGLE_VERT;
808 break;
809 }
810
811 text->SetVertJustify( static_cast<EDA_TEXT_VJUSTIFY_T>( vjustify ) );
812 text->SetHorizJustify( static_cast<EDA_TEXT_HJUSTIFY_T>( hjustify ) );
813 text->SetTextAngle( angle );
814 }
815
816
ParseLabel(const std::map<wxString,wxString> & aProperties)817 void SCH_ALTIUM_PLUGIN::ParseLabel( const std::map<wxString, wxString>& aProperties )
818 {
819 ASCH_LABEL elem( aProperties );
820
821 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
822 {
823 std::map<wxString, wxString> variableMap = {
824 { "APPLICATION_BUILDNUMBER", "KICAD_VERSION" },
825 { "SHEETNUMBER", "#" },
826 { "SHEETTOTAL", "##" },
827 { "TITLE", "TITLE" }, // 1:1 maps are sort of useless, but it makes it
828 { "REVISION", "REVISION" }, // easier to see that the list is complete
829 { "DATE", "ISSUE_DATE" },
830 { "CURRENTDATE", "CURRENT_DATE" },
831 { "COMPANYNAME", "COMPANY" },
832 { "DOCUMENTNAME", "FILENAME" },
833 { "PROJECTNAME", "PROJECTNAME" },
834 };
835
836 wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
837 SCH_TEXT* textItem = new SCH_TEXT( elem.location + m_sheetOffset, kicadText );
838
839 SetTextPositioning( textItem, elem.justification, elem.orientation );
840
841 size_t fontId = static_cast<int>( elem.fontId );
842
843 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
844 {
845 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
846 textItem->SetItalic( font.italic );
847 textItem->SetBold( font.bold );
848 textItem->SetTextSize( { font.size / 2, font.size / 2 } );
849 }
850
851 textItem->SetFlags(IS_NEW );
852 m_currentSheet->GetScreen()->Append( textItem );
853 }
854 else
855 {
856 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
857
858 if( libSymbolIt == m_libSymbols.end() )
859 {
860 // TODO: e.g. can depend on Template (RECORD=39
861 m_reporter->Report( wxString::Format( _( "Label's owner (%d) not found." ),
862 elem.ownerindex ),
863 RPT_SEVERITY_ERROR );
864 return;
865 }
866
867 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
868 LIB_TEXT* textItem = new LIB_TEXT( libSymbolIt->second );
869 libSymbolIt->second->AddDrawItem( textItem );
870
871 textItem->SetUnit( elem.ownerpartid );
872
873 textItem->SetPosition( GetRelativePosition( elem.location + m_sheetOffset, symbol ) );
874 textItem->SetText( elem.text );
875 SetTextPositioning( textItem, elem.justification, elem.orientation );
876
877 size_t fontId = static_cast<int>( elem.fontId );
878
879 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
880 {
881 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
882 textItem->SetItalic( font.italic );
883 textItem->SetBold( font.bold );
884 textItem->SetTextSize( { font.size / 2, font.size / 2 } );
885 }
886 }
887 }
888
889
ParseTextFrame(const std::map<wxString,wxString> & aProperties)890 void SCH_ALTIUM_PLUGIN::ParseTextFrame( const std::map<wxString, wxString>& aProperties )
891 {
892 ASCH_TEXT_FRAME elem( aProperties );
893
894 SCH_TEXT* text = new SCH_TEXT( elem.location + m_sheetOffset, elem.text );
895
896 switch( elem.alignment )
897 {
898 default:
899 case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
900 text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
901 break;
902 case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
903 // No support for centered text in Eeschema yet...
904 text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
905 break;
906 case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
907 text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::LEFT );
908 break;
909 }
910
911 // TODO: set size and word-wrap once KiCad supports wrapped text.
912
913 // TODO: set border and background color once KiCad supports them.
914
915 size_t fontId = static_cast<int>( elem.fontId );
916
917 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
918 {
919 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
920 text->SetItalic( font.italic );
921 text->SetBold( font.bold );
922 text->SetTextSize( { font.size / 2, font.size / 2 } );
923 }
924
925 text->SetFlags( IS_NEW );
926 m_currentSheet->GetScreen()->Append( text );
927 }
928
929
ParseNote(const std::map<wxString,wxString> & aProperties)930 void SCH_ALTIUM_PLUGIN::ParseNote( const std::map<wxString, wxString>& aProperties )
931 {
932 ASCH_NOTE elem( aProperties );
933
934 SCH_TEXT* text = new SCH_TEXT( elem.location + m_sheetOffset, elem.text );
935
936 switch( elem.alignment )
937 {
938 default:
939 case ASCH_TEXT_FRAME_ALIGNMENT::LEFT:
940 text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
941 break;
942 case ASCH_TEXT_FRAME_ALIGNMENT::CENTER:
943 // No support for centered text in Eeschema yet...
944 text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::RIGHT );
945 break;
946 case ASCH_TEXT_FRAME_ALIGNMENT::RIGHT:
947 text->SetLabelSpinStyle( LABEL_SPIN_STYLE::SPIN::LEFT );
948 break;
949 }
950
951 // TODO: set size and word-wrap once KiCad supports wrapped text.
952
953 // TODO: set border and background color once KiCad supports them.
954
955 // TODO: need some sort of property system for storing author....
956
957 size_t fontId = static_cast<int>( elem.fontId );
958
959 if( m_altiumSheet && fontId > 0 && fontId <= m_altiumSheet->fonts.size() )
960 {
961 const ASCH_SHEET_FONT& font = m_altiumSheet->fonts.at( fontId - 1 );
962 text->SetItalic( font.italic );
963 text->SetBold( font.bold );
964 text->SetTextSize( { font.size / 2, font.size / 2 } );
965 }
966
967 text->SetFlags( IS_NEW );
968 m_currentSheet->GetScreen()->Append( text );
969 }
970
971
ParseBezier(const std::map<wxString,wxString> & aProperties)972 void SCH_ALTIUM_PLUGIN::ParseBezier( const std::map<wxString, wxString>& aProperties )
973 {
974 ASCH_BEZIER elem( aProperties );
975
976 if( elem.points.size() < 2 )
977 {
978 m_reporter->Report( wxString::Format( _( "Bezier has %d control points. At least 2 are "
979 "expected." ),
980 static_cast<int>( elem.points.size() ) ),
981 RPT_SEVERITY_WARNING );
982 return;
983 }
984
985 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
986 {
987 for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
988 {
989 if( i + 2 == elem.points.size() )
990 {
991 // special case: single line
992 SCH_LINE* line = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
993 SCH_LAYER_ID::LAYER_NOTES );
994
995 line->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
996 line->SetLineWidth( elem.lineWidth );
997 line->SetLineStyle( PLOT_DASH_TYPE::SOLID );
998
999 line->SetFlags( IS_NEW );
1000 m_currentSheet->GetScreen()->Append( line );
1001 }
1002 else
1003 {
1004 // simulate Bezier using line segments
1005 std::vector<wxPoint> bezierPoints;
1006 std::vector<wxPoint> polyPoints;
1007
1008 for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
1009 bezierPoints.push_back( elem.points.at( j ) + m_sheetOffset );
1010
1011 BEZIER_POLY converter( bezierPoints );
1012 converter.GetPoly( polyPoints );
1013
1014 for( size_t k = 0; k + 1 < polyPoints.size(); k++ )
1015 {
1016 SCH_LINE* line = new SCH_LINE( polyPoints.at( k ) + m_sheetOffset,
1017 SCH_LAYER_ID::LAYER_NOTES );
1018
1019 line->SetEndPoint( polyPoints.at( k + 1 ) + m_sheetOffset );
1020 line->SetLineWidth( elem.lineWidth );
1021
1022 line->SetFlags( IS_NEW );
1023 m_currentSheet->GetScreen()->Append( line );
1024 }
1025 }
1026 }
1027 }
1028 else
1029 {
1030 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1031
1032 if( libSymbolIt == m_libSymbols.end() )
1033 {
1034 // TODO: e.g. can depend on Template (RECORD=39
1035 m_reporter->Report( wxString::Format( _( "Bezier's owner (%d) not found." ),
1036 elem.ownerindex ),
1037 RPT_SEVERITY_ERROR );
1038 return;
1039 }
1040
1041 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
1042 return;
1043
1044 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
1045
1046 for( size_t i = 0; i + 1 < elem.points.size(); i += 3 )
1047 {
1048 if( i + 2 == elem.points.size() )
1049 {
1050 // special case: single line
1051 LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
1052 libSymbolIt->second->AddDrawItem( line );
1053
1054 line->SetUnit( elem.ownerpartid );
1055
1056 for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
1057 {
1058 line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
1059 symbol ) );
1060 }
1061
1062 line->SetWidth( elem.lineWidth );
1063 }
1064 else if( i + 3 == elem.points.size() )
1065 {
1066 // TODO: special case of a single line with an extra point?
1067 // I haven't a clue what this is all about, but the sample document we have in
1068 // https://gitlab.com/kicad/code/kicad/-/issues/8974 responds best by treating it
1069 // as another single line special case.
1070 LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
1071 libSymbolIt->second->AddDrawItem( line );
1072
1073 line->SetUnit( elem.ownerpartid );
1074
1075 for( size_t j = i; j < elem.points.size() && j < i + 2; j++ )
1076 {
1077 line->AddPoint( GetRelativePosition( elem.points.at( j ) + m_sheetOffset,
1078 symbol ) );
1079 }
1080
1081 line->SetWidth( elem.lineWidth );
1082 }
1083 else
1084 {
1085 // Bezier always has exactly 4 control points
1086 LIB_SHAPE* bezier = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::BEZIER );
1087 libSymbolIt->second->AddDrawItem( bezier );
1088
1089 bezier->SetUnit( elem.ownerpartid );
1090
1091 for( size_t j = i; j < elem.points.size() && j < i + 4; j++ )
1092 {
1093 wxPoint pos = GetRelativePosition( elem.points.at( j ) + m_sheetOffset, symbol );
1094
1095 switch( j - i )
1096 {
1097 case 0: bezier->SetStart( pos ); break;
1098 case 1: bezier->SetBezierC1( pos ); break;
1099 case 2: bezier->SetBezierC2( pos ); break;
1100 case 3: bezier->SetEnd( pos ); break;
1101 default: break; // Can't get here but silence warnings
1102 }
1103 }
1104
1105 bezier->SetWidth( elem.lineWidth );
1106 }
1107 }
1108 }
1109 }
1110
1111
ParsePolyline(const std::map<wxString,wxString> & aProperties)1112 void SCH_ALTIUM_PLUGIN::ParsePolyline( const std::map<wxString, wxString>& aProperties )
1113 {
1114 ASCH_POLYLINE elem( aProperties );
1115
1116 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
1117 {
1118 PLOT_DASH_TYPE dashType = PLOT_DASH_TYPE::DEFAULT;
1119 switch( elem.linestyle )
1120 {
1121 default:
1122 case ASCH_POLYLINE_LINESTYLE::SOLID: dashType = PLOT_DASH_TYPE::SOLID; break;
1123 case ASCH_POLYLINE_LINESTYLE::DASHED: dashType = PLOT_DASH_TYPE::DASH; break;
1124 case ASCH_POLYLINE_LINESTYLE::DOTTED: dashType = PLOT_DASH_TYPE::DOT; break;
1125 case ASCH_POLYLINE_LINESTYLE::DASH_DOTTED: dashType = PLOT_DASH_TYPE::DASHDOT; break;
1126 }
1127
1128 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
1129 {
1130 SCH_LINE* line = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
1131 SCH_LAYER_ID::LAYER_NOTES );
1132
1133 line->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
1134 line->SetLineWidth( elem.lineWidth );
1135 line->SetLineStyle( dashType );
1136
1137 line->SetFlags( IS_NEW );
1138 m_currentSheet->GetScreen()->Append( line );
1139 }
1140 }
1141 else
1142 {
1143 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1144
1145 if( libSymbolIt == m_libSymbols.end() )
1146 {
1147 // TODO: e.g. can depend on Template (RECORD=39
1148 m_reporter->Report( wxString::Format( _( "Polyline's owner (%d) not found." ),
1149 elem.ownerindex ),
1150 RPT_SEVERITY_ERROR );
1151 return;
1152 }
1153
1154 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
1155 return;
1156
1157 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
1158 LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
1159 libSymbolIt->second->AddDrawItem( line );
1160
1161 line->SetUnit( elem.ownerpartid );
1162
1163 for( wxPoint& point : elem.points )
1164 line->AddPoint( GetRelativePosition( point + m_sheetOffset, symbol ) );
1165
1166 line->SetWidth( elem.lineWidth );
1167 }
1168 }
1169
1170
ParsePolygon(const std::map<wxString,wxString> & aProperties)1171 void SCH_ALTIUM_PLUGIN::ParsePolygon( const std::map<wxString, wxString>& aProperties )
1172 {
1173 ASCH_POLYGON elem( aProperties );
1174
1175 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
1176 {
1177 // TODO: we cannot fill this polygon, only draw it for now
1178 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
1179 {
1180 SCH_LINE* line = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
1181 SCH_LAYER_ID::LAYER_NOTES );
1182 line->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
1183 line->SetLineWidth( elem.lineWidth );
1184 line->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1185
1186 line->SetFlags( IS_NEW );
1187 m_currentSheet->GetScreen()->Append( line );
1188 }
1189
1190 // close polygon
1191 SCH_LINE* line = new SCH_LINE( elem.points.front() + m_sheetOffset,
1192 SCH_LAYER_ID::LAYER_NOTES );
1193 line->SetEndPoint( elem.points.back() + m_sheetOffset );
1194 line->SetLineWidth( elem.lineWidth );
1195 line->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1196
1197 line->SetFlags( IS_NEW );
1198 m_currentSheet->GetScreen()->Append( line );
1199 }
1200 else
1201 {
1202 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1203
1204 if( libSymbolIt == m_libSymbols.end() )
1205 {
1206 // TODO: e.g. can depend on Template (RECORD=39
1207 m_reporter->Report( wxString::Format( _( "Polygon's owner (%d) not found." ),
1208 elem.ownerindex ),
1209 RPT_SEVERITY_ERROR );
1210 return;
1211 }
1212
1213 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
1214 return;
1215
1216 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
1217 LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
1218 libSymbolIt->second->AddDrawItem( line );
1219
1220 line->SetUnit( elem.ownerpartid );
1221
1222 for( wxPoint& point : elem.points )
1223 line->AddPoint( GetRelativePosition( point + m_sheetOffset, symbol ) );
1224
1225 line->AddPoint( GetRelativePosition( elem.points.front() + m_sheetOffset, symbol ) );
1226
1227 line->SetWidth( elem.lineWidth );
1228
1229 if( !elem.isSolid )
1230 line->SetFillMode( FILL_T::NO_FILL );
1231 else if( elem.color == elem.areacolor )
1232 line->SetFillMode( FILL_T::FILLED_SHAPE );
1233 else
1234 line->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1235 }
1236 }
1237
1238
ParseRoundRectangle(const std::map<wxString,wxString> & aProperties)1239 void SCH_ALTIUM_PLUGIN::ParseRoundRectangle( const std::map<wxString, wxString>& aProperties )
1240 {
1241 ASCH_ROUND_RECTANGLE elem( aProperties );
1242
1243 wxPoint sheetTopRight = elem.topRight + m_sheetOffset;
1244 wxPoint sheetBottomLeft = elem.bottomLeft + m_sheetOffset;
1245
1246 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
1247 {
1248 const wxPoint topLeft = { sheetBottomLeft.x, sheetTopRight.y };
1249 const wxPoint bottomRight = { sheetTopRight.x, sheetBottomLeft.y };
1250
1251 // TODO: we cannot fill this rectangle, only draw it for now
1252 // TODO: misses rounded edges
1253 SCH_LINE* lineTop = new SCH_LINE( sheetTopRight, SCH_LAYER_ID::LAYER_NOTES );
1254 lineTop->SetEndPoint( topLeft );
1255 lineTop->SetLineWidth( elem.lineWidth );
1256 lineTop->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1257 lineTop->SetFlags( IS_NEW );
1258 m_currentSheet->GetScreen()->Append( lineTop );
1259
1260 SCH_LINE* lineBottom = new SCH_LINE( sheetBottomLeft, SCH_LAYER_ID::LAYER_NOTES );
1261 lineBottom->SetEndPoint( bottomRight );
1262 lineBottom->SetLineWidth( elem.lineWidth );
1263 lineBottom->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1264 lineBottom->SetFlags( IS_NEW );
1265 m_currentSheet->GetScreen()->Append( lineBottom );
1266
1267 SCH_LINE* lineRight = new SCH_LINE( sheetTopRight, SCH_LAYER_ID::LAYER_NOTES );
1268 lineRight->SetEndPoint( bottomRight );
1269 lineRight->SetLineWidth( elem.lineWidth );
1270 lineRight->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1271 lineRight->SetFlags( IS_NEW );
1272 m_currentSheet->GetScreen()->Append( lineRight );
1273
1274 SCH_LINE* lineLeft = new SCH_LINE( sheetBottomLeft, SCH_LAYER_ID::LAYER_NOTES );
1275 lineLeft->SetEndPoint( topLeft );
1276 lineLeft->SetLineWidth( elem.lineWidth );
1277 lineLeft->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1278 lineLeft->SetFlags( IS_NEW );
1279 m_currentSheet->GetScreen()->Append( lineLeft );
1280 }
1281 else
1282 {
1283 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1284
1285 if( libSymbolIt == m_libSymbols.end() )
1286 {
1287 // TODO: e.g. can depend on Template (RECORD=39
1288 m_reporter->Report( wxString::Format( _( "Rounded rectangle's owner (%d) not found." ),
1289 elem.ownerindex ),
1290 RPT_SEVERITY_ERROR );
1291 return;
1292 }
1293
1294 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
1295 return;
1296
1297 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
1298 // TODO: misses rounded edges
1299 LIB_SHAPE* rect = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::RECT );
1300 libSymbolIt->second->AddDrawItem( rect );
1301
1302 rect->SetUnit( elem.ownerpartid );
1303
1304 rect->SetPosition( GetRelativePosition( elem.topRight + m_sheetOffset, symbol ) );
1305 rect->SetEnd( GetRelativePosition( elem.bottomLeft + m_sheetOffset, symbol ) );
1306 rect->SetWidth( elem.lineWidth );
1307
1308 if( !elem.isSolid )
1309 rect->SetFillMode( FILL_T::NO_FILL );
1310 else if( elem.color == elem.areacolor )
1311 rect->SetFillMode( FILL_T::FILLED_SHAPE );
1312 else
1313 rect->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1314 }
1315 }
1316
1317
ParseArc(const std::map<wxString,wxString> & aProperties)1318 void SCH_ALTIUM_PLUGIN::ParseArc( const std::map<wxString, wxString>& aProperties )
1319 {
1320 ASCH_ARC elem( aProperties );
1321
1322 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
1323 {
1324 m_reporter->Report( _( "Arcs on schematic not currently supported." ),
1325 RPT_SEVERITY_ERROR );
1326 }
1327 else
1328 {
1329 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1330
1331 if( libSymbolIt == m_libSymbols.end() )
1332 {
1333 // TODO: e.g. can depend on Template (RECORD=39
1334 m_reporter->Report( wxString::Format( _( "Arc's owner (%d) not found." ),
1335 elem.ownerindex ),
1336 RPT_SEVERITY_ERROR );
1337 return;
1338 }
1339
1340 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
1341 return;
1342
1343 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
1344
1345 if( elem.startAngle == 0 && ( elem.endAngle == 0 || elem.endAngle == 360 ) )
1346 {
1347 LIB_SHAPE* circle = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::CIRCLE );
1348 libSymbolIt->second->AddDrawItem( circle );
1349
1350 circle->SetUnit( elem.ownerpartid );
1351
1352 circle->SetPosition( GetRelativePosition( elem.center + m_sheetOffset, symbol ) );
1353 circle->SetEnd( circle->GetPosition() + wxPoint( elem.radius, 0 ) );
1354 circle->SetWidth( elem.lineWidth );
1355 }
1356 else
1357 {
1358 LIB_SHAPE* arc = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::ARC );
1359 libSymbolIt->second->AddDrawItem( arc );
1360 arc->SetUnit( elem.ownerpartid );
1361
1362 arc->SetCenter( GetRelativePosition( elem.center + m_sheetOffset, symbol ) );
1363
1364 wxPoint arcStart( elem.radius, 0 );
1365 RotatePoint( &arcStart.x, &arcStart.y, -elem.startAngle * 10.0 );
1366 arcStart += arc->GetCenter();
1367 arc->SetStart( arcStart );
1368
1369 wxPoint arcEnd( elem.radius, 0 );
1370 RotatePoint( &arcEnd.x, &arcEnd.y, -elem.endAngle * 10.0 );
1371 arcEnd += arc->GetCenter();
1372 arc->SetEnd( arcEnd );
1373
1374 arc->SetWidth( elem.lineWidth );
1375 }
1376 }
1377 }
1378
1379
ParseLine(const std::map<wxString,wxString> & aProperties)1380 void SCH_ALTIUM_PLUGIN::ParseLine( const std::map<wxString, wxString>& aProperties )
1381 {
1382 ASCH_LINE elem( aProperties );
1383
1384 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
1385 {
1386 // close polygon
1387 SCH_LINE* line = new SCH_LINE( elem.point1 + m_sheetOffset, SCH_LAYER_ID::LAYER_NOTES );
1388 line->SetEndPoint( elem.point2 + m_sheetOffset );
1389 line->SetLineWidth( elem.lineWidth );
1390 line->SetLineStyle( PLOT_DASH_TYPE::SOLID ); // TODO?
1391
1392 line->SetFlags( IS_NEW );
1393 m_currentSheet->GetScreen()->Append( line );
1394 }
1395 else
1396 {
1397 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1398
1399 if( libSymbolIt == m_libSymbols.end() )
1400 {
1401 // TODO: e.g. can depend on Template (RECORD=39
1402 m_reporter->Report( wxString::Format( _( "Line's owner (%d) not found." ),
1403 elem.ownerindex ),
1404 RPT_SEVERITY_ERROR );
1405 return;
1406 }
1407
1408 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
1409 return;
1410
1411 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
1412 LIB_SHAPE* line = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::POLY );
1413 libSymbolIt->second->AddDrawItem( line );
1414
1415 line->SetUnit( elem.ownerpartid );
1416
1417 line->AddPoint( GetRelativePosition( elem.point1 + m_sheetOffset, symbol ) );
1418 line->AddPoint( GetRelativePosition( elem.point2 + m_sheetOffset, symbol ) );
1419
1420 line->SetWidth( elem.lineWidth );
1421 }
1422 }
1423
1424
ParseRectangle(const std::map<wxString,wxString> & aProperties)1425 void SCH_ALTIUM_PLUGIN::ParseRectangle( const std::map<wxString, wxString>& aProperties )
1426 {
1427 ASCH_RECTANGLE elem( aProperties );
1428
1429 wxPoint sheetTopRight = elem.topRight + m_sheetOffset;
1430 wxPoint sheetBottomLeft = elem.bottomLeft + m_sheetOffset;
1431
1432 if( elem.ownerpartid == ALTIUM_COMPONENT_NONE )
1433 {
1434 const wxPoint topLeft = { sheetBottomLeft.x, sheetTopRight.y };
1435 const wxPoint bottomRight = { sheetTopRight.x, sheetBottomLeft.y };
1436
1437 // TODO: we cannot fill this rectangle, only draw it for now
1438 SCH_LINE* lineTop = new SCH_LINE( sheetTopRight, SCH_LAYER_ID::LAYER_NOTES );
1439 lineTop->SetEndPoint( topLeft );
1440 lineTop->SetLineWidth( elem.lineWidth );
1441 lineTop->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1442 lineTop->SetFlags( IS_NEW );
1443 m_currentSheet->GetScreen()->Append( lineTop );
1444
1445 SCH_LINE* lineBottom = new SCH_LINE( sheetBottomLeft, SCH_LAYER_ID::LAYER_NOTES );
1446 lineBottom->SetEndPoint( bottomRight );
1447 lineBottom->SetLineWidth( elem.lineWidth );
1448 lineBottom->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1449 lineBottom->SetFlags( IS_NEW );
1450 m_currentSheet->GetScreen()->Append( lineBottom );
1451
1452 SCH_LINE* lineRight = new SCH_LINE( sheetTopRight, SCH_LAYER_ID::LAYER_NOTES );
1453 lineRight->SetEndPoint( bottomRight );
1454 lineRight->SetLineWidth( elem.lineWidth );
1455 lineRight->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1456 lineRight->SetFlags( IS_NEW );
1457 m_currentSheet->GetScreen()->Append( lineRight );
1458
1459 SCH_LINE* lineLeft = new SCH_LINE( sheetBottomLeft, SCH_LAYER_ID::LAYER_NOTES );
1460 lineLeft->SetEndPoint( topLeft );
1461 lineLeft->SetLineWidth( elem.lineWidth );
1462 lineLeft->SetLineStyle( PLOT_DASH_TYPE::SOLID );
1463 lineLeft->SetFlags( IS_NEW );
1464 m_currentSheet->GetScreen()->Append( lineLeft );
1465 }
1466 else
1467 {
1468 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
1469
1470 if( libSymbolIt == m_libSymbols.end() )
1471 {
1472 // TODO: e.g. can depend on Template (RECORD=39
1473 m_reporter->Report( wxString::Format( _( "Rectangle's owner (%d) not found." ),
1474 elem.ownerindex ),
1475 RPT_SEVERITY_ERROR );
1476 return;
1477 }
1478
1479 if( !IsComponentPartVisible( elem.ownerindex, elem.ownerpartdisplaymode ) )
1480 return;
1481
1482 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
1483 LIB_SHAPE* rect = new LIB_SHAPE( libSymbolIt->second, SHAPE_T::RECT );
1484 libSymbolIt->second->AddDrawItem( rect );
1485
1486 rect->SetUnit( elem.ownerpartid );
1487
1488 rect->SetPosition( GetRelativePosition( sheetTopRight, symbol ) );
1489 rect->SetEnd( GetRelativePosition( sheetBottomLeft, symbol ) );
1490 rect->SetWidth( elem.lineWidth );
1491
1492 if( !elem.isSolid )
1493 rect->SetFillMode( FILL_T::NO_FILL );
1494 else if( elem.color == elem.areacolor )
1495 rect->SetFillMode( FILL_T::FILLED_SHAPE );
1496 else
1497 rect->SetFillMode( FILL_T::FILLED_WITH_BG_BODYCOLOR );
1498 }
1499 }
1500
1501
ParseSheetSymbol(int aIndex,const std::map<wxString,wxString> & aProperties)1502 void SCH_ALTIUM_PLUGIN::ParseSheetSymbol( int aIndex,
1503 const std::map<wxString, wxString>& aProperties )
1504 {
1505 ASCH_SHEET_SYMBOL elem( aProperties );
1506
1507 SCH_SHEET* sheet = new SCH_SHEET( m_currentSheet, elem.location + m_sheetOffset );
1508 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
1509
1510 sheet->SetSize( elem.size );
1511 sheet->SetBorderColor( GetColorFromInt( elem.color ) );
1512
1513 if( elem.isSolid )
1514 sheet->SetBackgroundColor( GetColorFromInt( elem.areacolor ) );
1515
1516 sheet->SetScreen( screen );
1517
1518 sheet->SetFlags( IS_NEW );
1519 m_currentSheet->GetScreen()->Append( sheet );
1520
1521 SCH_SHEET_PATH sheetpath;
1522 m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
1523 sheetpath.push_back( sheet );
1524
1525 sheet->AddInstance( sheetpath );
1526 sheet->SetPageNumber( sheetpath, "#" ); // We'll update later if we find a pageNumber
1527 // record for it
1528
1529 m_sheets.insert( { aIndex, sheet } );
1530 }
1531
1532
ParseSheetEntry(const std::map<wxString,wxString> & aProperties)1533 void SCH_ALTIUM_PLUGIN::ParseSheetEntry( const std::map<wxString, wxString>& aProperties )
1534 {
1535 ASCH_SHEET_ENTRY elem( aProperties );
1536
1537 const auto& sheetIt = m_sheets.find( elem.ownerindex );
1538
1539 if( sheetIt == m_sheets.end() )
1540 {
1541 m_reporter->Report( wxString::Format( _( "Sheet entry's owner (%d) not found." ),
1542 elem.ownerindex ),
1543 RPT_SEVERITY_ERROR );
1544 return;
1545 }
1546
1547 SCH_SHEET_PIN* sheetPin = new SCH_SHEET_PIN( sheetIt->second );
1548 sheetIt->second->AddPin( sheetPin );
1549
1550 sheetPin->SetText( elem.name );
1551 sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_UNSPECIFIED );
1552 //sheetPin->SetLabelSpinStyle( getSpinStyle( term.OrientAngle, false ) );
1553 //sheetPin->SetPosition( getKiCadPoint( term.Position ) );
1554
1555 wxPoint pos = sheetIt->second->GetPosition();
1556 wxSize size = sheetIt->second->GetSize();
1557
1558 switch( elem.side )
1559 {
1560 default:
1561 case ASCH_SHEET_ENTRY_SIDE::LEFT:
1562 sheetPin->SetPosition( { pos.x, pos.y + elem.distanceFromTop } );
1563 sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
1564 sheetPin->SetSide( SHEET_SIDE::LEFT );
1565 break;
1566 case ASCH_SHEET_ENTRY_SIDE::RIGHT:
1567 sheetPin->SetPosition( { pos.x + size.x, pos.y + elem.distanceFromTop } );
1568 sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
1569 sheetPin->SetSide( SHEET_SIDE::RIGHT );
1570 break;
1571 case ASCH_SHEET_ENTRY_SIDE::TOP:
1572 sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y } );
1573 sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::UP );
1574 sheetPin->SetSide( SHEET_SIDE::TOP );
1575 break;
1576 case ASCH_SHEET_ENTRY_SIDE::BOTTOM:
1577 sheetPin->SetPosition( { pos.x + elem.distanceFromTop, pos.y + size.y } );
1578 sheetPin->SetLabelSpinStyle( LABEL_SPIN_STYLE::BOTTOM );
1579 sheetPin->SetSide( SHEET_SIDE::BOTTOM );
1580 break;
1581 }
1582
1583 switch( elem.iotype )
1584 {
1585 default:
1586 case ASCH_PORT_IOTYPE::UNSPECIFIED:
1587 sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_UNSPECIFIED );
1588 break;
1589 case ASCH_PORT_IOTYPE::OUTPUT:
1590 sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_OUTPUT );
1591 break;
1592 case ASCH_PORT_IOTYPE::INPUT:
1593 sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_INPUT );
1594 break;
1595 case ASCH_PORT_IOTYPE::BIDI:
1596 sheetPin->SetShape( PINSHEETLABEL_SHAPE::PS_BIDI );
1597 break;
1598 }
1599 }
1600
1601
HelperGeneratePowerPortGraphics(LIB_SYMBOL * aKsymbol,ASCH_POWER_PORT_STYLE aStyle,REPORTER * aReporter)1602 wxPoint HelperGeneratePowerPortGraphics( LIB_SYMBOL* aKsymbol, ASCH_POWER_PORT_STYLE aStyle,
1603 REPORTER* aReporter )
1604 {
1605 if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE || aStyle == ASCH_POWER_PORT_STYLE::ARROW )
1606 {
1607 LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1608 aKsymbol->AddDrawItem( line1 );
1609 line1->SetWidth( Mils2iu( 10 ) );
1610 line1->AddPoint( { 0, 0 } );
1611 line1->AddPoint( { 0, Mils2iu( -50 ) } );
1612
1613 if( aStyle == ASCH_POWER_PORT_STYLE::CIRCLE )
1614 {
1615 LIB_SHAPE* circle = new LIB_SHAPE( aKsymbol, SHAPE_T::CIRCLE );
1616 aKsymbol->AddDrawItem( circle );
1617 circle->SetWidth( Mils2iu( 5 ) );
1618 circle->SetPosition( { Mils2iu( 0 ), Mils2iu( -75 ) } );
1619 circle->SetEnd( circle->GetPosition() + wxPoint( Mils2iu( 25 ), 0 ) );
1620 }
1621 else
1622 {
1623 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1624 aKsymbol->AddDrawItem( line2 );
1625 line2->SetWidth( Mils2iu( 10 ) );
1626 line2->AddPoint( { Mils2iu( -25 ), Mils2iu( -50 ) } );
1627 line2->AddPoint( { Mils2iu( 25 ), Mils2iu( -50 ) } );
1628 line2->AddPoint( { Mils2iu( 0 ), Mils2iu( -100 ) } );
1629 line2->AddPoint( { Mils2iu( -25 ), Mils2iu( -50 ) } );
1630 }
1631
1632 return { 0, Mils2iu( 150 ) };
1633 }
1634 else if( aStyle == ASCH_POWER_PORT_STYLE::WAVE )
1635 {
1636 LIB_SHAPE* line = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1637 aKsymbol->AddDrawItem( line );
1638 line->SetWidth( Mils2iu( 10 ) );
1639 line->AddPoint( { 0, 0 } );
1640 line->AddPoint( { 0, Mils2iu( -72 ) } );
1641
1642 LIB_SHAPE* bezier = new LIB_SHAPE( aKsymbol, SHAPE_T::BEZIER );
1643 aKsymbol->AddDrawItem( bezier );
1644 bezier->SetWidth( Mils2iu( 5 ) );
1645 bezier->AddPoint( { Mils2iu( 30 ), Mils2iu( -50 ) } );
1646 bezier->AddPoint( { Mils2iu( 30 ), Mils2iu( -87 ) } );
1647 bezier->AddPoint( { Mils2iu( -30 ), Mils2iu( -63 ) } );
1648 bezier->AddPoint( { Mils2iu( -30 ), Mils2iu( -100 ) } );
1649
1650 return { 0, Mils2iu( 150 ) };
1651 }
1652 else if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND
1653 || aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND
1654 || aStyle == ASCH_POWER_PORT_STYLE::EARTH
1655 || aStyle == ASCH_POWER_PORT_STYLE::GOST_ARROW )
1656 {
1657 LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1658 aKsymbol->AddDrawItem( line1 );
1659 line1->SetWidth( Mils2iu( 10 ) );
1660 line1->AddPoint( { 0, 0 } );
1661 line1->AddPoint( { 0, Mils2iu( -100 ) } );
1662
1663 if( aStyle == ASCH_POWER_PORT_STYLE::POWER_GROUND )
1664 {
1665 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1666 aKsymbol->AddDrawItem( line2 );
1667 line2->SetWidth( Mils2iu( 10 ) );
1668 line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
1669 line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -100 ) } );
1670
1671 LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1672 aKsymbol->AddDrawItem( line3 );
1673 line3->SetWidth( Mils2iu( 10 ) );
1674 line3->AddPoint( { Mils2iu( -70 ), Mils2iu( -130 ) } );
1675 line3->AddPoint( { Mils2iu( 70 ), Mils2iu( -130 ) } );
1676
1677 LIB_SHAPE* line4 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1678 aKsymbol->AddDrawItem( line4 );
1679 line4->SetWidth( Mils2iu( 10 ) );
1680 line4->AddPoint( { Mils2iu( -40 ), Mils2iu( -160 ) } );
1681 line4->AddPoint( { Mils2iu( 40 ), Mils2iu( -160 ) } );
1682
1683 LIB_SHAPE* line5 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1684 aKsymbol->AddDrawItem( line5 );
1685 line5->SetWidth( Mils2iu( 10 ) );
1686 line5->AddPoint( { Mils2iu( -10 ), Mils2iu( -190 ) } );
1687 line5->AddPoint( { Mils2iu( 10 ), Mils2iu( -190 ) } );
1688 }
1689 else if( aStyle == ASCH_POWER_PORT_STYLE::SIGNAL_GROUND )
1690 {
1691 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1692 aKsymbol->AddDrawItem( line2 );
1693 line2->SetWidth( Mils2iu( 10 ) );
1694 line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
1695 line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -100 ) } );
1696 line2->AddPoint( { Mils2iu( 0 ), Mils2iu( -200 ) } );
1697 line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
1698 }
1699 else if( aStyle == ASCH_POWER_PORT_STYLE::EARTH )
1700 {
1701 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1702 aKsymbol->AddDrawItem( line2 );
1703 line2->SetWidth( Mils2iu( 10 ) );
1704 line2->AddPoint( { Mils2iu( -150 ), Mils2iu( -200 ) } );
1705 line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -100 ) } );
1706 line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -100 ) } );
1707 line2->AddPoint( { Mils2iu( 50 ), Mils2iu( -200 ) } );
1708
1709 LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1710 aKsymbol->AddDrawItem( line3 );
1711 line3->SetWidth( Mils2iu( 10 ) );
1712 line3->AddPoint( { Mils2iu( 0 ), Mils2iu( -100 ) } );
1713 line3->AddPoint( { Mils2iu( -50 ), Mils2iu( -200 ) } );
1714 }
1715 else // ASCH_POWER_PORT_STYLE::GOST_ARROW
1716 {
1717 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1718 aKsymbol->AddDrawItem( line2 );
1719 line2->SetWidth( Mils2iu( 10 ) );
1720 line2->AddPoint( { Mils2iu( -25 ), Mils2iu( -50 ) } );
1721 line2->AddPoint( { Mils2iu( 0 ), Mils2iu( -100 ) } );
1722 line2->AddPoint( { Mils2iu( 25 ), Mils2iu( -50 ) } );
1723
1724 return { 0, Mils2iu( 150 ) }; // special case
1725 }
1726
1727 return { 0, Mils2iu( 250 ) };
1728 }
1729 else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_POWER_GROUND
1730 || aStyle == ASCH_POWER_PORT_STYLE::GOST_EARTH )
1731 {
1732 LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1733 aKsymbol->AddDrawItem( line1 );
1734 line1->SetWidth( Mils2iu( 10 ) );
1735 line1->AddPoint( { 0, 0 } );
1736 line1->AddPoint( { 0, Mils2iu( -160 ) } );
1737
1738 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1739 aKsymbol->AddDrawItem( line2 );
1740 line2->SetWidth( Mils2iu( 10 ) );
1741 line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -160 ) } );
1742 line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -160 ) } );
1743
1744 LIB_SHAPE* line3 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1745 aKsymbol->AddDrawItem( line3 );
1746 line3->SetWidth( Mils2iu( 10 ) );
1747 line3->AddPoint( { Mils2iu( -60 ), Mils2iu( -200 ) } );
1748 line3->AddPoint( { Mils2iu( 60 ), Mils2iu( -200 ) } );
1749
1750 LIB_SHAPE* line4 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1751 aKsymbol->AddDrawItem( line4 );
1752 line4->SetWidth( Mils2iu( 10 ) );
1753 line4->AddPoint( { Mils2iu( -20 ), Mils2iu( -240 ) } );
1754 line4->AddPoint( { Mils2iu( 20 ), Mils2iu( -240 ) } );
1755
1756 if( aStyle == ASCH_POWER_PORT_STYLE::GOST_POWER_GROUND )
1757 return { 0, Mils2iu( 300 ) };
1758
1759 LIB_SHAPE* circle = new LIB_SHAPE( aKsymbol, SHAPE_T::CIRCLE );
1760 aKsymbol->AddDrawItem( circle );
1761 circle->SetWidth( Mils2iu( 10 ) );
1762 circle->SetPosition( { Mils2iu( 0 ), Mils2iu( -160 ) } );
1763 circle->SetEnd( circle->GetPosition() + wxPoint( Mils2iu( 120 ), 0 ) );
1764
1765 return { 0, Mils2iu( 350 ) };
1766 }
1767 else if( aStyle == ASCH_POWER_PORT_STYLE::GOST_BAR )
1768 {
1769 LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1770 aKsymbol->AddDrawItem( line1 );
1771 line1->SetWidth( Mils2iu( 10 ) );
1772 line1->AddPoint( { 0, 0 } );
1773 line1->AddPoint( { 0, Mils2iu( -200 ) } );
1774
1775 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1776 aKsymbol->AddDrawItem( line2 );
1777 line2->SetWidth( Mils2iu( 10 ) );
1778 line2->AddPoint( { Mils2iu( -100 ), Mils2iu( -200 ) } );
1779 line2->AddPoint( { Mils2iu( 100 ), Mils2iu( -200 ) } );
1780
1781 return { 0, Mils2iu( 250 ) };
1782 }
1783 else
1784 {
1785 if( aStyle != ASCH_POWER_PORT_STYLE::BAR )
1786 {
1787 aReporter->Report( _( "Power Port has unknown style, use bar instead." ),
1788 RPT_SEVERITY_WARNING );
1789 }
1790
1791 LIB_SHAPE* line1 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1792 aKsymbol->AddDrawItem( line1 );
1793 line1->SetWidth( Mils2iu( 10 ) );
1794 line1->AddPoint( { 0, 0 } );
1795 line1->AddPoint( { 0, Mils2iu( -100 ) } );
1796
1797 LIB_SHAPE* line2 = new LIB_SHAPE( aKsymbol, SHAPE_T::POLY );
1798 aKsymbol->AddDrawItem( line2 );
1799 line2->SetWidth( Mils2iu( 10 ) );
1800 line2->AddPoint( { Mils2iu( -50 ), Mils2iu( -100 ) } );
1801 line2->AddPoint( { Mils2iu( 50 ), Mils2iu( -100 ) } );
1802
1803 return { 0, Mils2iu( 150 ) };
1804 }
1805 }
1806
1807
ParsePowerPort(const std::map<wxString,wxString> & aProperties)1808 void SCH_ALTIUM_PLUGIN::ParsePowerPort( const std::map<wxString, wxString>& aProperties )
1809 {
1810 ASCH_POWER_PORT elem( aProperties );
1811 LIB_ID libId = AltiumToKiCadLibID( getLibName(), elem.text );
1812 LIB_SYMBOL* libSymbol = nullptr;
1813
1814 const auto& powerSymbolIt = m_powerSymbols.find( elem.text );
1815
1816 if( powerSymbolIt != m_powerSymbols.end() )
1817 {
1818 libSymbol = powerSymbolIt->second; // cache hit
1819 }
1820 else
1821 {
1822 libSymbol = new LIB_SYMBOL( wxEmptyString );
1823 libSymbol->SetPower();
1824 libSymbol->SetName( elem.text );
1825 libSymbol->GetReferenceField().SetText( "#PWR" );
1826 libSymbol->GetValueField().SetText( elem.text );
1827 libSymbol->GetValueField().SetVisible( true );
1828 libSymbol->SetDescription( wxString::Format( _( "Power symbol creates a global "
1829 "label with name '%s'" ), elem.text ) );
1830 libSymbol->SetKeyWords( "power-flag" );
1831 libSymbol->SetLibId( libId );
1832
1833 // generate graphic
1834 LIB_PIN* pin = new LIB_PIN( libSymbol );
1835 libSymbol->AddDrawItem( pin );
1836
1837 pin->SetName( elem.text );
1838 pin->SetPosition( { 0, 0 } );
1839 pin->SetLength( 0 );
1840
1841 // marks the pin as a global label
1842 pin->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
1843 pin->SetVisible( false );
1844
1845 wxPoint valueFieldPos = HelperGeneratePowerPortGraphics( libSymbol, elem.style, m_reporter );
1846
1847 libSymbol->GetValueField().SetPosition( valueFieldPos );
1848
1849 // this has to be done after parsing the LIB_SYMBOL!
1850 m_pi->SaveSymbol( getLibFileName().GetFullPath(), libSymbol, m_properties.get() );
1851 m_powerSymbols.insert( { elem.text, libSymbol } );
1852 }
1853
1854 SCH_SHEET_PATH sheetpath;
1855 m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
1856
1857 // each symbol has its own powerSymbolIt for now
1858 SCH_SYMBOL* symbol = new SCH_SYMBOL();
1859 symbol->SetRef( &sheetpath, "#PWR?" );
1860 symbol->SetValue( elem.text );
1861 symbol->SetLibId( libId );
1862 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
1863
1864 SCH_FIELD* valueField = symbol->GetField( VALUE_FIELD );
1865 valueField->SetVisible( elem.showNetName );
1866
1867 // TODO: Why do I need to set this a second time?
1868 valueField->SetPosition( libSymbol->GetValueField().GetPosition() );
1869
1870 symbol->SetPosition( elem.location + m_sheetOffset );
1871
1872 switch( elem.orientation )
1873 {
1874 case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
1875 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_90 );
1876 valueField->SetTextAngle( TEXT_ANGLE_VERT );
1877 valueField->SetHorizJustify( EDA_TEXT_HJUSTIFY_T::GR_TEXT_HJUSTIFY_RIGHT );
1878 break;
1879 case ASCH_RECORD_ORIENTATION::UPWARDS:
1880 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_180 );
1881 valueField->SetTextAngle( TEXT_ANGLE_HORIZ );
1882 valueField->SetHorizJustify( EDA_TEXT_HJUSTIFY_T::GR_TEXT_HJUSTIFY_CENTER );
1883 break;
1884 case ASCH_RECORD_ORIENTATION::LEFTWARDS:
1885 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_270 );
1886 valueField->SetTextAngle( TEXT_ANGLE_VERT );
1887 valueField->SetHorizJustify( EDA_TEXT_HJUSTIFY_T::GR_TEXT_HJUSTIFY_RIGHT );
1888 break;
1889 case ASCH_RECORD_ORIENTATION::DOWNWARDS:
1890 symbol->SetOrientation( SYMBOL_ORIENTATION_T::SYM_ORIENT_0 );
1891 valueField->SetTextAngle( TEXT_ANGLE_HORIZ );
1892 valueField->SetHorizJustify( EDA_TEXT_HJUSTIFY_T::GR_TEXT_HJUSTIFY_CENTER );
1893 break;
1894 default:
1895 m_reporter->Report( _( "Pin has unexpected orientation." ), RPT_SEVERITY_WARNING );
1896 break;
1897 }
1898
1899 m_currentSheet->GetScreen()->Append( symbol );
1900 }
1901
1902
ParsePort(const ASCH_PORT & aElem)1903 void SCH_ALTIUM_PLUGIN::ParsePort( const ASCH_PORT& aElem )
1904 {
1905 bool isHarness = !aElem.harnessType.IsEmpty();
1906 wxPoint start = aElem.location + m_sheetOffset;
1907 wxPoint end = start;
1908
1909 switch( aElem.style )
1910 {
1911 default:
1912 case ASCH_PORT_STYLE::NONE_HORIZONTAL:
1913 case ASCH_PORT_STYLE::LEFT:
1914 case ASCH_PORT_STYLE::RIGHT:
1915 case ASCH_PORT_STYLE::LEFT_RIGHT:
1916 end.x += aElem.width;
1917 break;
1918 case ASCH_PORT_STYLE::NONE_VERTICAL:
1919 case ASCH_PORT_STYLE::TOP:
1920 case ASCH_PORT_STYLE::BOTTOM:
1921 case ASCH_PORT_STYLE::TOP_BOTTOM:
1922 end.y -= aElem.width;
1923 break;
1924 }
1925
1926 // Check which connection points exists in the schematic
1927 SCH_SCREEN* screen = m_currentSheet->GetScreen();
1928
1929 bool startIsWireTerminal = screen->IsTerminalPoint( start, LAYER_WIRE );
1930 bool startIsBusTerminal = screen->IsTerminalPoint( start, LAYER_BUS );
1931
1932 bool endIsWireTerminal = screen->IsTerminalPoint( end, LAYER_WIRE );
1933 bool endIsBusTerminal = screen->IsTerminalPoint( end, LAYER_BUS );
1934
1935 // check if any of the points is a terminal point
1936 // TODO: there seems a problem to detect approximated connections towards component pins?
1937 bool connectionFound = startIsWireTerminal
1938 || startIsBusTerminal
1939 || endIsWireTerminal
1940 || endIsBusTerminal;
1941
1942 if( !isHarness && !connectionFound )
1943 {
1944 m_reporter->Report( wxString::Format( _( "Port %s has no connections." ), aElem.name ),
1945 RPT_SEVERITY_WARNING );
1946 }
1947
1948 // Select label position. In case both match, we will add a line later.
1949 wxPoint position = ( startIsWireTerminal || startIsBusTerminal ) ? start : end;
1950 SCH_TEXT* label;
1951
1952 if( isHarness )
1953 {
1954 wxString name = wxT( "HARNESS: " ) + aElem.name;
1955
1956 if( aElem.harnessType != aElem.name )
1957 name += wxString::Format( wxT( " (%s)" ), aElem.harnessType );
1958
1959 label = new SCH_TEXT( position, name );
1960 }
1961 // TODO: detect correct label type depending on sheet settings, etc.
1962 //{
1963 // label = new SCH_HIERLABEL( elem.location + m_sheetOffset, elem.name );
1964 //}
1965 else
1966 {
1967
1968 label = new SCH_GLOBALLABEL( position, aElem.name );
1969 }
1970
1971 switch( aElem.iotype )
1972 {
1973 default:
1974 case ASCH_PORT_IOTYPE::UNSPECIFIED:
1975 label->SetShape( PINSHEETLABEL_SHAPE::PS_UNSPECIFIED );
1976 break;
1977 case ASCH_PORT_IOTYPE::OUTPUT:
1978 label->SetShape( PINSHEETLABEL_SHAPE::PS_OUTPUT );
1979 break;
1980 case ASCH_PORT_IOTYPE::INPUT:
1981 label->SetShape( PINSHEETLABEL_SHAPE::PS_INPUT );
1982 break;
1983 case ASCH_PORT_IOTYPE::BIDI:
1984 label->SetShape( PINSHEETLABEL_SHAPE::PS_BIDI );
1985 break;
1986 }
1987
1988 switch( aElem.style )
1989 {
1990 default:
1991 case ASCH_PORT_STYLE::NONE_HORIZONTAL:
1992 case ASCH_PORT_STYLE::LEFT:
1993 case ASCH_PORT_STYLE::RIGHT:
1994 case ASCH_PORT_STYLE::LEFT_RIGHT:
1995 if( ( startIsWireTerminal || startIsBusTerminal ) )
1996 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
1997 else
1998 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
1999 break;
2000 case ASCH_PORT_STYLE::NONE_VERTICAL:
2001 case ASCH_PORT_STYLE::TOP:
2002 case ASCH_PORT_STYLE::BOTTOM:
2003 case ASCH_PORT_STYLE::TOP_BOTTOM:
2004 if( ( startIsWireTerminal || startIsBusTerminal ) )
2005 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::UP );
2006 else
2007 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::BOTTOM );
2008 break;
2009 }
2010
2011 label->SetFlags( IS_NEW );
2012 m_currentSheet->GetScreen()->Append( label );
2013
2014 // This is a hack, for the case both connection points are valid: add a small wire
2015 if( ( startIsWireTerminal && endIsWireTerminal ) )
2016 {
2017 SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_WIRE );
2018 wire->SetEndPoint( end );
2019 wire->SetLineWidth( Mils2iu( 2 ) );
2020 wire->SetFlags( IS_NEW );
2021 m_currentSheet->GetScreen()->Append( wire );
2022 }
2023 else if( startIsBusTerminal && endIsBusTerminal )
2024 {
2025 SCH_LINE* wire = new SCH_LINE( start, SCH_LAYER_ID::LAYER_BUS );
2026 wire->SetEndPoint( end );
2027 wire->SetLineWidth( Mils2iu( 2 ) );
2028 wire->SetFlags( IS_NEW );
2029 m_currentSheet->GetScreen()->Append( wire );
2030 }
2031 }
2032
2033
ParseNoERC(const std::map<wxString,wxString> & aProperties)2034 void SCH_ALTIUM_PLUGIN::ParseNoERC( const std::map<wxString, wxString>& aProperties )
2035 {
2036 ASCH_NO_ERC elem( aProperties );
2037
2038 if( elem.isActive )
2039 {
2040 SCH_NO_CONNECT* noConnect = new SCH_NO_CONNECT( elem.location + m_sheetOffset );
2041
2042 noConnect->SetFlags( IS_NEW );
2043 m_currentSheet->GetScreen()->Append( noConnect );
2044 }
2045 }
2046
2047
ParseNetLabel(const std::map<wxString,wxString> & aProperties)2048 void SCH_ALTIUM_PLUGIN::ParseNetLabel( const std::map<wxString, wxString>& aProperties )
2049 {
2050 ASCH_NET_LABEL elem( aProperties );
2051
2052 SCH_LABEL* label = new SCH_LABEL( elem.location + m_sheetOffset, elem.text );
2053
2054 switch( elem.orientation )
2055 {
2056 case ASCH_RECORD_ORIENTATION::RIGHTWARDS:
2057 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::RIGHT );
2058 break;
2059 case ASCH_RECORD_ORIENTATION::UPWARDS:
2060 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::UP );
2061 break;
2062 case ASCH_RECORD_ORIENTATION::LEFTWARDS:
2063 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::LEFT );
2064 break;
2065 case ASCH_RECORD_ORIENTATION::DOWNWARDS:
2066 label->SetLabelSpinStyle( LABEL_SPIN_STYLE::BOTTOM );
2067 break;
2068 default:
2069 break;
2070 }
2071
2072 label->SetFlags( IS_NEW );
2073 m_currentSheet->GetScreen()->Append( label );
2074 }
2075
2076
ParseBus(const std::map<wxString,wxString> & aProperties)2077 void SCH_ALTIUM_PLUGIN::ParseBus( const std::map<wxString, wxString>& aProperties )
2078 {
2079 ASCH_BUS elem( aProperties );
2080
2081 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
2082 {
2083 SCH_LINE* bus = new SCH_LINE( elem.points.at( i ) + m_sheetOffset,
2084 SCH_LAYER_ID::LAYER_BUS );
2085 bus->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
2086 bus->SetLineWidth( elem.lineWidth );
2087
2088 bus->SetFlags( IS_NEW );
2089 m_currentSheet->GetScreen()->Append( bus );
2090 }
2091 }
2092
2093
ParseWire(const std::map<wxString,wxString> & aProperties)2094 void SCH_ALTIUM_PLUGIN::ParseWire( const std::map<wxString, wxString>& aProperties )
2095 {
2096 ASCH_WIRE elem( aProperties );
2097
2098 for( size_t i = 0; i + 1 < elem.points.size(); i++ )
2099 {
2100 SCH_LINE* wire =
2101 new SCH_LINE( elem.points.at( i ) + m_sheetOffset, SCH_LAYER_ID::LAYER_WIRE );
2102 wire->SetEndPoint( elem.points.at( i + 1 ) + m_sheetOffset );
2103 wire->SetLineWidth( elem.lineWidth );
2104
2105 wire->SetFlags( IS_NEW );
2106 m_currentSheet->GetScreen()->Append( wire );
2107 }
2108 }
2109
2110
ParseJunction(const std::map<wxString,wxString> & aProperties)2111 void SCH_ALTIUM_PLUGIN::ParseJunction( const std::map<wxString, wxString>& aProperties )
2112 {
2113 ASCH_JUNCTION elem( aProperties );
2114
2115 SCH_JUNCTION* junction = new SCH_JUNCTION( elem.location + m_sheetOffset );
2116
2117 junction->SetFlags( IS_NEW );
2118 m_currentSheet->GetScreen()->Append( junction );
2119 }
2120
2121
ParseImage(const std::map<wxString,wxString> & aProperties)2122 void SCH_ALTIUM_PLUGIN::ParseImage( const std::map<wxString, wxString>& aProperties )
2123 {
2124 ASCH_IMAGE elem( aProperties );
2125
2126 wxPoint center = ( elem.location + elem.corner ) / 2 + m_sheetOffset;
2127 std::unique_ptr<SCH_BITMAP> bitmap = std::make_unique<SCH_BITMAP>( center );
2128
2129 if( elem.embedimage )
2130 {
2131 const ASCH_STORAGE_FILE* storageFile = GetFileFromStorage( elem.filename );
2132
2133 if( !storageFile )
2134 {
2135 wxString msg = wxString::Format( _( "Embedded file %s not found in storage." ),
2136 elem.filename );
2137 m_reporter->Report( msg, RPT_SEVERITY_ERROR );
2138 return;
2139 }
2140
2141 wxString storagePath = wxFileName::CreateTempFileName( "kicad_import_" );
2142
2143 // As wxZlibInputStream is not seekable, we need to write a temporary file
2144 wxMemoryInputStream fileStream( storageFile->data.data(), storageFile->data.size() );
2145 wxZlibInputStream zlibInputStream( fileStream );
2146 wxFFileOutputStream outputStream( storagePath );
2147 outputStream.Write( zlibInputStream );
2148 outputStream.Close();
2149
2150 if( !bitmap->ReadImageFile( storagePath ) )
2151 {
2152 m_reporter->Report( wxString::Format( _( "Error reading image %s." ), storagePath ),
2153 RPT_SEVERITY_ERROR );
2154 return;
2155 }
2156
2157 // Remove temporary file
2158 wxRemoveFile( storagePath );
2159 }
2160 else
2161 {
2162 if( !wxFileExists( elem.filename ) )
2163 {
2164 m_reporter->Report( wxString::Format( _( "File not found %s." ), elem.filename ),
2165 RPT_SEVERITY_ERROR );
2166 return;
2167 }
2168
2169 if( !bitmap->ReadImageFile( elem.filename ) )
2170 {
2171 m_reporter->Report( wxString::Format( _( "Error reading image %s." ), elem.filename ),
2172 RPT_SEVERITY_ERROR );
2173 return;
2174 }
2175 }
2176
2177 // we only support one scale, thus we need to select one in case it does not keep aspect ratio
2178 wxSize currentImageSize = bitmap->GetSize();
2179 wxPoint expectedImageSize = elem.location - elem.corner;
2180 double scaleX = std::abs( static_cast<double>( expectedImageSize.x ) / currentImageSize.x );
2181 double scaleY = std::abs( static_cast<double>( expectedImageSize.y ) / currentImageSize.y );
2182 bitmap->SetImageScale( std::min( scaleX, scaleY ) );
2183
2184 bitmap->SetFlags( IS_NEW );
2185 m_currentSheet->GetScreen()->Append( bitmap.release() );
2186 }
2187
2188
ParseSheet(const std::map<wxString,wxString> & aProperties)2189 void SCH_ALTIUM_PLUGIN::ParseSheet( const std::map<wxString, wxString>& aProperties )
2190 {
2191 m_altiumSheet = std::make_unique<ASCH_SHEET>( aProperties );
2192
2193 PAGE_INFO pageInfo;
2194
2195 bool isPortrait = m_altiumSheet->sheetOrientation == ASCH_SHEET_WORKSPACEORIENTATION::PORTRAIT;
2196
2197 switch( m_altiumSheet->sheetSize )
2198 {
2199 default:
2200 case ASCH_SHEET_SIZE::A4: pageInfo.SetType( "A4", isPortrait ); break;
2201 case ASCH_SHEET_SIZE::A3: pageInfo.SetType( "A3", isPortrait ); break;
2202 case ASCH_SHEET_SIZE::A2: pageInfo.SetType( "A2", isPortrait ); break;
2203 case ASCH_SHEET_SIZE::A1: pageInfo.SetType( "A1", isPortrait ); break;
2204 case ASCH_SHEET_SIZE::A0: pageInfo.SetType( "A0", isPortrait ); break;
2205 case ASCH_SHEET_SIZE::A: pageInfo.SetType( "A", isPortrait ); break;
2206 case ASCH_SHEET_SIZE::B: pageInfo.SetType( "B", isPortrait ); break;
2207 case ASCH_SHEET_SIZE::C: pageInfo.SetType( "C", isPortrait ); break;
2208 case ASCH_SHEET_SIZE::D: pageInfo.SetType( "D", isPortrait ); break;
2209 case ASCH_SHEET_SIZE::E: pageInfo.SetType( "E", isPortrait ); break;
2210 case ASCH_SHEET_SIZE::LETTER: pageInfo.SetType( "USLetter", isPortrait ); break;
2211 case ASCH_SHEET_SIZE::LEGAL: pageInfo.SetType( "USLegal", isPortrait ); break;
2212 case ASCH_SHEET_SIZE::TABLOID: pageInfo.SetType( "A3", isPortrait ); break;
2213 case ASCH_SHEET_SIZE::ORCAD_A: pageInfo.SetType( "A", isPortrait ); break;
2214 case ASCH_SHEET_SIZE::ORCAD_B: pageInfo.SetType( "B", isPortrait ); break;
2215 case ASCH_SHEET_SIZE::ORCAD_C: pageInfo.SetType( "C", isPortrait ); break;
2216 case ASCH_SHEET_SIZE::ORCAD_D: pageInfo.SetType( "D", isPortrait ); break;
2217 case ASCH_SHEET_SIZE::ORCAD_E: pageInfo.SetType( "E", isPortrait ); break;
2218 }
2219
2220 m_currentSheet->GetScreen()->SetPageSettings( pageInfo );
2221
2222 m_sheetOffset = { 0, pageInfo.GetHeightIU() };
2223 }
2224
2225
ParseSheetName(const std::map<wxString,wxString> & aProperties)2226 void SCH_ALTIUM_PLUGIN::ParseSheetName( const std::map<wxString, wxString>& aProperties )
2227 {
2228 ASCH_SHEET_NAME elem( aProperties );
2229
2230 const auto& sheetIt = m_sheets.find( elem.ownerindex );
2231
2232 if( sheetIt == m_sheets.end() )
2233 {
2234 m_reporter->Report( wxString::Format( _( "Sheetname's owner (%d) not found." ),
2235 elem.ownerindex ),
2236 RPT_SEVERITY_ERROR );
2237 return;
2238 }
2239
2240 SCH_FIELD& sheetNameField = sheetIt->second->GetFields()[SHEETNAME];
2241
2242 sheetNameField.SetPosition( elem.location + m_sheetOffset );
2243 sheetNameField.SetText( elem.text );
2244 sheetNameField.SetVisible( !elem.isHidden );
2245 SetTextPositioning( &sheetNameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
2246 }
2247
2248
ParseFileName(const std::map<wxString,wxString> & aProperties)2249 void SCH_ALTIUM_PLUGIN::ParseFileName( const std::map<wxString, wxString>& aProperties )
2250 {
2251 ASCH_FILE_NAME elem( aProperties );
2252
2253 const auto& sheetIt = m_sheets.find( elem.ownerindex );
2254
2255 if( sheetIt == m_sheets.end() )
2256 {
2257 m_reporter->Report( wxString::Format( _( "Filename's owner (%d) not found." ),
2258 elem.ownerindex ),
2259 RPT_SEVERITY_ERROR );
2260 return;
2261 }
2262
2263 SCH_FIELD& filenameField = sheetIt->second->GetFields()[SHEETFILENAME];
2264
2265 filenameField.SetPosition( elem.location + m_sheetOffset );
2266
2267 // If last symbols are ".sChDoC", change them to ".kicad_sch"
2268 if( ( elem.text.Right( GetFileExtension().length() + 1 ).Lower() )
2269 == ( "." + GetFileExtension().Lower() ) )
2270 {
2271 elem.text.RemoveLast( GetFileExtension().length() );
2272 elem.text += KiCadSchematicFileExtension;
2273 }
2274
2275 filenameField.SetText( elem.text );
2276
2277 filenameField.SetVisible( !elem.isHidden );
2278 SetTextPositioning( &filenameField, ASCH_LABEL_JUSTIFICATION::BOTTOM_LEFT, elem.orientation );
2279 }
2280
2281
ParseDesignator(const std::map<wxString,wxString> & aProperties)2282 void SCH_ALTIUM_PLUGIN::ParseDesignator( const std::map<wxString, wxString>& aProperties )
2283 {
2284 ASCH_DESIGNATOR elem( aProperties );
2285
2286 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2287
2288 if( libSymbolIt == m_libSymbols.end() )
2289 {
2290 // TODO: e.g. can depend on Template (RECORD=39
2291 m_reporter->Report( wxString::Format( _( "Designator's owner (%d) not found." ),
2292 elem.ownerindex ),
2293 RPT_SEVERITY_ERROR );
2294 return;
2295 }
2296
2297 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
2298 SCH_SHEET_PATH sheetpath;
2299 m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
2300
2301 symbol->SetRef( &sheetpath, elem.text );
2302
2303 SCH_FIELD* refField = symbol->GetField( REFERENCE_FIELD );
2304
2305 refField->SetPosition( elem.location + m_sheetOffset );
2306 refField->SetVisible( true );
2307 SetTextPositioning( refField, elem.justification, elem.orientation );
2308 }
2309
2310
ParseBusEntry(const std::map<wxString,wxString> & aProperties)2311 void SCH_ALTIUM_PLUGIN::ParseBusEntry( const std::map<wxString, wxString>& aProperties )
2312 {
2313 ASCH_BUS_ENTRY elem( aProperties );
2314
2315 SCH_BUS_WIRE_ENTRY* busWireEntry = new SCH_BUS_WIRE_ENTRY( elem.location + m_sheetOffset );
2316
2317 wxPoint vector = elem.corner - elem.location;
2318 busWireEntry->SetSize( { vector.x, vector.y } );
2319
2320 busWireEntry->SetFlags( IS_NEW );
2321 m_currentSheet->GetScreen()->Append( busWireEntry );
2322 }
2323
2324
ParseParameter(const std::map<wxString,wxString> & aProperties)2325 void SCH_ALTIUM_PLUGIN::ParseParameter( const std::map<wxString, wxString>& aProperties )
2326 {
2327 ASCH_PARAMETER elem( aProperties );
2328
2329 // TODO: fill in replacements from variant, sheet and project
2330 std::map<wxString, wxString> variableMap = {
2331 { "COMMENT", "VALUE" },
2332 { "VALUE", "ALTIUM_VALUE" },
2333 };
2334
2335 if( elem.ownerindex <= 0 && elem.ownerpartid == ALTIUM_COMPONENT_NONE )
2336 {
2337 // This is some sheet parameter
2338 if( elem.text == "*" )
2339 return; // indicates parameter not set?
2340
2341 wxString paramName = elem.name.Upper();
2342
2343 if( paramName == "SHEETNUMBER" )
2344 {
2345 SCH_SHEET_PATH sheetpath;
2346 m_rootSheet->LocatePathOfScreen( m_currentSheet->GetScreen(), &sheetpath );
2347
2348 m_rootSheet->SetPageNumber( sheetpath, elem.text );
2349 }
2350 else if( paramName == "TITLE" )
2351 {
2352 m_currentTitleBlock->SetTitle( elem.text );
2353 }
2354 else if( paramName == "REVISION" )
2355 {
2356 m_currentTitleBlock->SetRevision( elem.text );
2357 }
2358 else if( paramName == "DATE" )
2359 {
2360 m_currentTitleBlock->SetDate( elem.text );
2361 }
2362 else if( paramName == "COMPANYNAME" )
2363 {
2364 m_currentTitleBlock->SetCompany( elem.text );
2365 }
2366 else
2367 {
2368 m_schematic->Prj().GetTextVars()[ paramName ] = elem.text;
2369 }
2370 }
2371 else
2372 {
2373 const auto& libSymbolIt = m_libSymbols.find( elem.ownerindex );
2374
2375 if( libSymbolIt == m_libSymbols.end() )
2376 {
2377 // TODO: e.g. can depend on Template (RECORD=39
2378 return;
2379 }
2380
2381 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
2382 SCH_FIELD* field = nullptr;
2383
2384 if( elem.name.Upper() == "COMMENT" )
2385 field = symbol->GetField( VALUE_FIELD );
2386 else
2387 {
2388 int fieldIdx = symbol->GetFieldCount();
2389 wxString fieldName = elem.name.Upper();
2390
2391 if( fieldName == "VALUE" )
2392 fieldName = "ALTIUM_VALUE";
2393
2394 field = symbol->AddField( SCH_FIELD( wxPoint(), fieldIdx, symbol, fieldName ) );
2395 }
2396
2397 wxString kicadText = AltiumSpecialStringsToKiCadVariables( elem.text, variableMap );
2398 field->SetText( kicadText );
2399 field->SetPosition( elem.location + m_sheetOffset );
2400 field->SetVisible( !elem.isHidden );
2401 SetTextPositioning( field, elem.justification, elem.orientation );
2402 }
2403 }
2404
2405
ParseImplementationList(int aIndex,const std::map<wxString,wxString> & aProperties)2406 void SCH_ALTIUM_PLUGIN::ParseImplementationList( int aIndex,
2407 const std::map<wxString, wxString>& aProperties )
2408 {
2409 ASCH_IMPLEMENTATION_LIST elem( aProperties );
2410
2411 m_altiumImplementationList.emplace( aIndex, elem.ownerindex );
2412 }
2413
2414
ParseImplementation(const std::map<wxString,wxString> & aProperties)2415 void SCH_ALTIUM_PLUGIN::ParseImplementation( const std::map<wxString, wxString>& aProperties )
2416 {
2417 ASCH_IMPLEMENTATION elem( aProperties );
2418
2419 // Only get footprint, currently assigned only
2420 if( ( elem.type == "PCBLIB" ) && ( elem.isCurrent ) )
2421 {
2422 const auto& implementationOwnerIt = m_altiumImplementationList.find( elem.ownerindex );
2423
2424 if( implementationOwnerIt == m_altiumImplementationList.end() )
2425 {
2426 m_reporter->Report( wxString::Format( _( "Implementation's owner (%d) not found." ),
2427 elem.ownerindex ),
2428 RPT_SEVERITY_ERROR );
2429 return;
2430 }
2431
2432 const auto& libSymbolIt = m_libSymbols.find( implementationOwnerIt->second );
2433
2434 if( libSymbolIt == m_libSymbols.end() )
2435 {
2436 m_reporter->Report( wxString::Format( _( "Footprint's owner (%d) not found." ),
2437 implementationOwnerIt->second ),
2438 RPT_SEVERITY_ERROR );
2439 return;
2440 }
2441
2442 LIB_ID fpLibId = AltiumToKiCadLibID( elem.libname, elem.name );
2443 wxArrayString fpFilters;
2444 fpFilters.Add( fpLibId.Format() );
2445
2446 libSymbolIt->second->SetFPFilters( fpFilters ); // TODO: not ideal as we overwrite it
2447
2448 SCH_SYMBOL* symbol = m_symbols.at( libSymbolIt->first );
2449
2450 symbol->SetFootprint( fpLibId.Format() );
2451 }
2452 }
2453