KiCad PCB EDA Suite
Loading...
Searching...
No Matches
cadstar_sch_archive_loader.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-2021 Roberto Fernandez Bautista <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
25
28
29#include <bus_alias.h>
30#include <core/mirror.h>
31#include <core/kicad_algo.h>
32#include <eda_text.h>
33#include <macros.h>
34#include <progress_reporter.h>
35#include <string_utils.h>
36#include <sch_bus_entry.h>
37#include <sch_edit_frame.h> //SYMBOL_ORIENTATION_T
38#include <sch_io/sch_io_mgr.h>
39#include <sch_junction.h>
40#include <sch_line.h>
41#include <sch_screen.h>
42#include <sch_shape.h>
43#include <sch_sheet.h>
44#include <sch_sheet_path.h>
45#include <sch_sheet_pin.h>
46#include <sch_label.h>
47#include <schematic.h>
48#include <sim/sim_model.h>
49#include <trigo.h>
51
52
53const wxString PartNameFieldName = "Part Name";
54const wxString PartNumberFieldName = "Part Number";
55const wxString PartVersionFieldName = "Part Version";
56const wxString PartAcceptanceFieldName = "Part Acceptance";
57
58
59wxString CADSTAR_SCH_ARCHIVE_LOADER::CreateLibName( const wxFileName& aFileName,
60 const SCH_SHEET* aRootSheet )
61{
62 wxString libName = aFileName.GetName();
63
64 if( libName.IsEmpty() && aRootSheet )
65 {
66 wxFileName fn( aRootSheet->GetFileName() );
67 libName = fn.GetName();
68 }
69
70 if( libName.IsEmpty() )
71 libName = "noname";
72
73 libName = LIB_ID::FixIllegalChars( libName, true ).wx_str();
74
75 return libName;
76}
77
78
79std::vector<LIB_SYMBOL*> CADSTAR_SCH_ARCHIVE_LOADER::LoadPartsLib( const wxString& aFilename )
80{
82 m_progressReporter->SetNumPhases( 3 ); // (0) Read csa, (1) Parse csa, (3) Load lib
83
84 Parse();
85
87
88 if( !p.CheckFileHeader( aFilename.utf8_string() ) )
89 THROW_IO_ERROR( _( "File does not appear to be a CADSTAR parts Library file" ) );
90
91 // TODO: we could add progress reporting for reading .lib
92 CADSTAR_PARTS_LIB_MODEL csLib = p.ReadFile( aFilename.utf8_string() );
93
95 {
96 m_progressReporter->BeginPhase( 2 );
97 long numSteps = csLib.m_PartEntries.size();
98 m_progressReporter->SetMaxProgress( numSteps );
99 }
100
101 std::vector<LIB_SYMBOL*> retVal;
102
103 for( const CADSTAR_PART_ENTRY& part : csLib.m_PartEntries )
104 {
105 std::unique_ptr<LIB_SYMBOL> loadedPart = loadLibPart( part );
106
107 checkPoint();
108
109 if( loadedPart )
110 retVal.push_back( loadedPart.release() );
111 }
112
113 return retVal;
114}
115
116
117std::unique_ptr<LIB_SYMBOL>
119{
120 wxString escapedPartName = EscapeString( aPart.m_Name, CTX_LIBID );
121 std::unique_ptr<LIB_SYMBOL> retSym;
122
123 int unit = 0;
124
125 for( const CADSTAR_PART_SYMBOL_ENTRY& sym : aPart.m_Symbols )
126 {
127 ++unit;
128 wxString alternateName = sym.m_SymbolAlternateName.value_or( "" );
129 SYMDEF_ID symbolID = getSymDefFromName( sym.m_SymbolName, alternateName );
130
131 if( !Library.SymbolDefinitions.count( symbolID ) )
132 {
133 m_reporter->Report( wxString::Format( _( "Unable to find symbol %s, referenced by part "
134 "%s. The part was not loaded." ),
135 generateLibName( sym.m_SymbolName, alternateName ),
136 aPart.m_Name ),
138
139 return nullptr;
140 }
141
142 // Load the graphical symbol for this gate
143 std::unique_ptr<LIB_SYMBOL> kiSymDef( loadSymdef( symbolID )->Duplicate() );
144
145 if( (int)sym.m_Pins.size() != kiSymDef->GetPinCount() )
146 {
147 m_reporter->Report( wxString::Format( _( "Inconsistent pin numbers in symbol %s "
148 "compared to the one defined in part %s. The "
149 "part was not loaded." ),
150 generateLibName( sym.m_SymbolName, alternateName ),
151 aPart.m_Name ),
153
154 return nullptr;
155 }
156
157 wxASSERT( m_symDefTerminalsMap.count( symbolID ) ); //loadSymDef should have populated this
158
159
160 // Update the pin numbers to match those defined in the Cadstar part
161 for( auto& [storedPinNum, termID] : m_symDefTerminalsMap[symbolID] )
162 {
163 wxCHECK( termID > 0 && sym.m_Pins.size() >= size_t( termID ), nullptr );
164 std::vector<SCH_PIN*> pins = kiSymDef->GetPinsByNumber( storedPinNum );
165 size_t termIdx = size_t( termID ) - 1;
166
167 // For now leave numerical pin number. Otherwise, when loading the
168 // .cpa file we won't be able to link up to the footprint pads, but if
169 // we solve this, we could then load alphanumeric pin numbers as below:
170 //
171 // if( aPart.m_PinNamesMap.count( termID ) )
172 // partPinNum = wxString( aPart.m_PinNamesMap.at( termID ) );
173 //
174 wxString partPinNum = wxString::Format( "%ld", sym.m_Pins[termIdx].m_Identifier );
175
176 for( SCH_PIN* pin : pins )
177 {
178 pin->SetNumber( partPinNum );
179
180 if( aPart.m_PinNamesMap.count( termID ) )
181 pin->SetName( HandleTextOverbar( aPart.m_PinNamesMap.at( termID ) ) );
182 else if( aPart.m_PinLabelsMap.count( termID ) )
183 pin->SetName( HandleTextOverbar( aPart.m_PinLabelsMap.at( termID ) ) );
184
185 pin->SetType( getKiCadPinType( sym.m_Pins[termIdx].m_Type ) );
186 }
187
188 // @todo: Load pin/gate swapping information once kicad supports this
189 }
190
191 if( unit == 1 )
192 {
193 wxCHECK( kiSymDef->GetUnitCount() == 1, nullptr );
194 // The first unit can just be moved to the part symbol
195 retSym = std::move( kiSymDef );
196
197 retSym->SetUnitCount( aPart.m_Symbols.size(), true );
198
199 retSym->SetName( escapedPartName );
200 retSym->GetReferenceField().SetText( aPart.m_ComponentStem );
201 retSym->GetValueField().SetText( aPart.m_Value.value_or( "" ) );
202 addNewFieldToSymbol( PartNameFieldName, retSym.get() )->SetText( aPart.m_Name );
203 retSym->SetDescription( aPart.m_Description.value_or( "" ) );
204
205 auto addFieldIfHasValue =
206 [&]( const wxString& name, const std::optional<std::string>& value )
207 {
208 if( value.has_value() )
209 addNewFieldToSymbol( name, retSym.get() )->SetText( value.value() );
210 };
211
212 addFieldIfHasValue( PartNumberFieldName, aPart.m_Number );
213 addFieldIfHasValue( PartVersionFieldName, aPart.m_Version );
214 addFieldIfHasValue( PartAcceptanceFieldName, aPart.m_AcceptancePartName );
215
216 setFootprintOnSymbol( retSym.get(), aPart.m_Pcb_component,
217 aPart.m_Pcb_alternate.value_or( "" ) );
218
219 if( aPart.m_SpiceModel.has_value() )
220 {
221 wxString modelVal = wxString::Format( "model=\"%s\"", aPart.m_SpiceModel.value() );
222 addNewFieldToSymbol( SIM_DEVICE_FIELD, retSym.get() )->SetText( "SPICE" );
223 addNewFieldToSymbol( SIM_PARAMS_FIELD, retSym.get() )->SetText( modelVal );
224 }
225
226 // Load all part attributes, regardless of original cadstar type, to the symbol
227
228 // @todo some cadstar part attributes have a "read-only" flag. We should load this
229 // when KiCad supports read-only fields.
230
231 for( auto& [fieldName, value] : aPart.m_UserAttributes )
232 addNewFieldToSymbol( fieldName, retSym.get() )->SetText( value );
233
234 for( auto& [fieldName, attrValue] : aPart.m_SchAttributes )
235 addNewFieldToSymbol( fieldName, retSym.get() )->SetText( attrValue.m_Value );
236
237 for( auto& [fieldName, attrValue] : aPart.m_PcbAttributes )
238 addNewFieldToSymbol( fieldName, retSym.get() )->SetText( attrValue.m_Value );
239
240 for( auto& [fieldName, attrValue] : aPart.m_SchAndPcbAttributes )
241 addNewFieldToSymbol( fieldName, retSym.get() )->SetText( attrValue.m_Value );
242
243 for( auto& [fieldName, attrValue] : aPart.m_PartAttributes )
244 addNewFieldToSymbol( fieldName, retSym.get() )->SetText( attrValue.m_Value );
245
246 // Load all hidden pins onto the first unit of the symbol in KiCad
247 // We load them in a spiral sequence, starting at the center of the symbol BBOX
248 VECTOR2I symCenter = retSym->GetBodyBoundingBox( unit, 0, false, false ).GetCenter();
249 symCenter.y = -symCenter.y; // need to invert the y coord for lib symbols.
250
251 VECTOR2I delta( 0, 1 );
252 VECTOR2I direction( 0, -1 );
253 int spacing = schIUScale.MilsToIU( 50 ); // for now, place on a 50mil grid
254
255 for( auto& [signalName, csPinVector] : aPart.m_HiddenPins )
256 {
257 for( const CADSTAR_PART_PIN& csPin : csPinVector )
258 {
259 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( retSym.get() );
260
261 long pinNum = csPin.m_Identifier;
262 pin->SetNumber( wxString::Format( "%ld", pinNum ) );
263 pin->SetName( signalName );
265
266 pin->SetVisible( false );
267
268 // Generate the coordinate for the pin. We don't want overlapping pins
269 // and ideally close to the center of the symbol, so we load pins in a
270 // spiral sequence around the center
271 if( delta.x == delta.y
272 || ( delta.x < 0 && delta.x == -delta.y )
273 || ( delta.x > 0 && delta.x == 1 - delta.y ) )
274 {
275 // change direction
276 direction = { -direction.y, direction.x };
277 }
278
279 delta += direction;
280 VECTOR2I offset = delta * spacing;
281 pin->SetPosition( symCenter + offset );
282 pin->SetLength( 0 ); //CADSTAR Pins are just a point (have no length)
283 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
284 pin->SetUnit( unit );
285 retSym->AddDrawItem( pin.release() );
286 }
287 }
288 }
289 else
290 { // Source: Dest:
291 copySymbolItems( kiSymDef.get(), retSym.get(), unit, false /* aOverrideFields */ );
292 }
293
294
295 retSym->SetShowPinNames( aPart.m_PinsVisible );
296 retSym->SetShowPinNumbers( aPart.m_PinsVisible );
297 }
298
299
300 return retSym;
301}
302
303
305 int aDestUnit, bool aOverrideFields )
306{
307 // Ensure there are no items on the unit we want to load onto
308 for( SCH_ITEM* item : aDestSym->GetUnitDrawItems( aDestUnit, 0 /* aBodyStyle */ ) )
309 aDestSym->RemoveDrawItem( item );
310
311 // Copy all draw items
312 for( SCH_ITEM* newItem : aSourceSym->GetUnitDrawItems( 1, 0 /* aBodyStyle */ ) )
313 {
314 SCH_ITEM* itemCopy = static_cast<SCH_ITEM*>( newItem->Clone() );
315 itemCopy->SetParent( aDestSym );
316 itemCopy->SetUnit( aDestUnit );
317 aDestSym->AddDrawItem( itemCopy );
318 }
319
320 //Copy / override all fields
321 if( aOverrideFields )
322 {
323 std::vector<SCH_FIELD*> fieldsToCopy;
324 aSourceSym->GetFields( fieldsToCopy );
325
326 for( SCH_FIELD* templateField : fieldsToCopy )
327 {
328 SCH_FIELD* appliedField = addNewFieldToSymbol( templateField->GetName(), aDestSym );
329 templateField->Copy( appliedField );
330 }
331 }
332}
333
334
336{
337 wxCHECK( aSchematic, /* void */ );
338
340 m_progressReporter->SetNumPhases( 3 ); // (0) Read file, (1) Parse file, (2) Load file
341
342 Parse();
343
344 checkDesignLimits(); // Throws if error found
345
346 // Assume the center at 0,0 since we are going to be translating the design afterwards anyway
347 m_designCenter = { 0, 0 };
348
349 m_schematic = aSchematic;
350 m_rootSheet = aRootSheet;
351
353 {
354 m_progressReporter->BeginPhase( 2 );
355 long numSteps = 11; // one step for each of below functions + one at the end of import
356
357 // Step 4 is by far the longest - add granularity in reporting
358 numSteps += Parts.PartDefinitions.size();
359
360 m_progressReporter->SetMaxProgress( numSteps );
361 }
362
363 loadTextVariables(); // Load text variables right at the start to ensure bounding box
364 // calculations work correctly for text items
365 checkPoint(); // Step 1
366 loadSheets();
367 checkPoint(); // Step 2
369 checkPoint(); // Step 3
371 checkPoint(); // Step 4, Subdivided into extra steps
373 checkPoint(); // Step 5
374 loadBusses();
375 checkPoint(); // Step 6
376 loadNets();
377 checkPoint(); // Step 7
378 loadFigures();
379 checkPoint(); // Step 8
380 loadTexts();
381 checkPoint(); // Step 9
383 checkPoint(); // Step 10
384
385 if( Schematic.VariantHierarchy.Variants.size() > 0 )
386 {
387 m_reporter->Report( wxString::Format( _( "The CADSTAR design contains variants which has "
388 "no KiCad equivalent. Only the master variant "
389 "('%s') was loaded." ),
390 Schematic.VariantHierarchy.Variants.at( "V0" ).Name ),
392 }
393
394 if( Schematic.Groups.size() > 0 )
395 {
396 m_reporter->Report( _( "The CADSTAR design contains grouped items which has no KiCad "
397 "equivalent. Any grouped items have been ungrouped." ),
399 }
400
401 if( Schematic.ReuseBlocks.size() > 0 )
402 {
403 m_reporter->Report( _( "The CADSTAR design contains re-use blocks which has no KiCad "
404 "equivalent. The re-use block information has been discarded during "
405 "the import." ),
407 }
408
409
410 // For all sheets, center all elements and re calculate the page size:
411 for( std::pair<LAYER_ID, SCH_SHEET*> sheetPair : m_sheetMap )
412 {
413 SCH_SHEET* sheet = sheetPair.second;
414
415 // Calculate the new sheet size.
416 BOX2I sheetBoundingBox;
417
418 for( SCH_ITEM* item : sheet->GetScreen()->Items() )
419 {
420 BOX2I bbox;
421
422 // Only use the visible fields of the symbols to calculate their bounding box
423 // (hidden fields could be very long and artificially enlarge the sheet bounding box)
424 if( item->Type() == SCH_SYMBOL_T )
425 {
426 SCH_SYMBOL* comp = static_cast<SCH_SYMBOL*>( item );
427 bbox = comp->GetBodyAndPinsBoundingBox();
428
429 for( const SCH_FIELD& field : comp->GetFields() )
430 {
431 if( field.IsVisible() )
432 bbox.Merge( field.GetBoundingBox() );
433 }
434 }
435 else if( item->Type() == SCH_TEXT_T )
436 {
437 SCH_TEXT* txtItem = static_cast<SCH_TEXT*>( item );
438 wxString txt = txtItem->GetText();
439
440 if( txt.Contains( "${" ) )
441 continue; // We can't calculate bounding box of text items with variables
442 else
443 bbox = txtItem->GetBoundingBox();
444 }
445 else
446 {
447 bbox = item->GetBoundingBox();
448 }
449
450 sheetBoundingBox.Merge( bbox );
451 }
452
453 // Find the screen grid of the original CADSTAR design
454 int grid = Assignments.Grids.ScreenGrid.Param1;
455
456 if( Assignments.Grids.ScreenGrid.Type == GRID_TYPE::FRACTIONALGRID )
457 grid = grid / Assignments.Grids.ScreenGrid.Param2;
458 else if( Assignments.Grids.ScreenGrid.Param2 > grid )
459 grid = Assignments.Grids.ScreenGrid.Param2;
460
462
463 auto roundToNearestGrid =
464 [&]( int aNumber ) -> int
465 {
466 int error = aNumber % grid;
467 int absError = sign( error ) * error;
468
469 if( absError > ( grid / 2 ) )
470 return aNumber + ( sign( error ) * grid ) - error;
471 else
472 return aNumber - error;
473 };
474
475 // When exporting to pdf, CADSTAR applies a margin of 3percent of the longest dimension (height
476 // or width) to all 4 sides (top, bottom, left right). For the import, we are also rounding
477 // the margin to the nearest grid, ensuring all items remain on the grid.
478 VECTOR2I targetSheetSize = sheetBoundingBox.GetSize();
479 int longestSide = std::max( targetSheetSize.x, targetSheetSize.y );
480 int margin = ( (double) longestSide * 0.03 );
481 margin = roundToNearestGrid( margin );
482 targetSheetSize += margin * 2;
483
484 // Update page size always
485 PAGE_INFO pageInfo = sheet->GetScreen()->GetPageSettings();
486 pageInfo.SetWidthMils( schIUScale.IUToMils( targetSheetSize.x ) );
487 pageInfo.SetHeightMils( schIUScale.IUToMils( targetSheetSize.y ) );
488
489 // Set the new sheet size.
490 sheet->GetScreen()->SetPageSettings( pageInfo );
491
492 VECTOR2I pageSizeIU = sheet->GetScreen()->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
493 VECTOR2I sheetcentre( pageSizeIU.x / 2, pageSizeIU.y / 2 );
494 VECTOR2I itemsCentre = sheetBoundingBox.Centre();
495
496 // round the translation to nearest point on the grid
497 VECTOR2I translation = sheetcentre - itemsCentre;
498 translation.x = roundToNearestGrid( translation.x );
499 translation.y = roundToNearestGrid( translation.y );
500
501 // Translate the items.
502 std::vector<SCH_ITEM*> allItems;
503
504 std::copy( sheet->GetScreen()->Items().begin(), sheet->GetScreen()->Items().end(),
505 std::back_inserter( allItems ) );
506
507 for( SCH_ITEM* item : allItems )
508 {
509 item->Move( translation );
510 item->ClearFlags();
511 sheet->GetScreen()->Update( item );
512 }
513 }
514
515 checkPoint();
516
517 m_reporter->Report( _( "CADSTAR fonts are different to the ones in KiCad. This will likely "
518 "result in alignment issues. Please review the imported text elements "
519 "carefully and correct manually if required." ),
521
522 m_reporter->Report( _( "The CADSTAR design has been imported successfully.\n"
523 "Please review the import errors and warnings (if any)." ) );
524}
525
526
528{
529 LONGPOINT designLimit = Assignments.Settings.DesignLimit;
530
531 //Note: can't use getKiCadPoint() due VECTOR2I being int - need long long to make the check
532 long long designSizeXkicad = (long long) designLimit.x / KiCadUnitDivider;
533 long long designSizeYkicad = (long long) designLimit.y / KiCadUnitDivider;
534
535 // Max size limited by the positive dimension of VECTOR2I (which is an int)
536 constexpr long long maxDesignSizekicad = std::numeric_limits<int>::max();
537
538 if( designSizeXkicad > maxDesignSizekicad || designSizeYkicad > maxDesignSizekicad )
539 {
540 THROW_IO_ERRORF( _( "The design is too large and cannot be imported into KiCad. \n"
541 "Please reduce the maximum design size in CADSTAR by navigating to: \n"
542 "Design Tab -> Properties -> Design Options -> Maximum Design Size. \n"
543 "Current Design size: %.2f, %.2f millimeters. \n" //format:allow
544 "Maximum permitted design size: %.2f, %.2f millimeters.\n" ), //format:allow
545 (double) designSizeXkicad / SCH_IU_PER_MM,
546 (double) designSizeYkicad / SCH_IU_PER_MM,
547 (double) maxDesignSizekicad / SCH_IU_PER_MM,
548 (double) maxDesignSizekicad / SCH_IU_PER_MM );
549 }
550}
551
552
554{
555 const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets();
556 SCH_SHEET_PATH rootPath;
557 rootPath.push_back( m_rootSheet );
558 rootPath.SetPageNumber( wxT( "1" ) );
559
560 if( orphanSheets.size() > 1 )
561 {
562 int x = 1;
563 int y = 1;
564
565 for( LAYER_ID sheetID : orphanSheets )
566 {
567 VECTOR2I pos( x * schIUScale.MilsToIU( 1000 ), y * schIUScale.MilsToIU( 1000 ) );
568 VECTOR2I siz( schIUScale.MilsToIU( 1000 ), schIUScale.MilsToIU( 1000 ) );
569
570 loadSheetAndChildSheets( sheetID, pos, siz, rootPath );
571
572 x += 2;
573
574 if( x > 10 ) // start next row
575 {
576 x = 1;
577 y += 2;
578 }
579 }
580 }
581 else if( orphanSheets.size() > 0 )
582 {
583 LAYER_ID rootSheetID = orphanSheets.at( 0 );
584
585 wxFileName loadedFilePath = wxFileName( Filename );
586
587 std::string filename = wxString::Format( "%s_%02d", loadedFilePath.GetName(),
588 getSheetNumber( rootSheetID ) )
589 .ToStdString();
590 ReplaceIllegalFileNameChars( filename );
591 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
592
593 wxFileName fn( m_schematic->Project().GetProjectPath() + filename );
594 m_rootSheet->GetScreen()->SetFileName( fn.GetFullPath() );
595
596 m_sheetMap.insert( { rootSheetID, m_rootSheet } );
597 loadChildSheets( rootSheetID, rootPath );
598 }
599 else if( Header.Format.Type == "SYMBOL" )
600 {
601 THROW_IO_ERROR( _( "The selected file is a CADSTAR symbol library. It does not contain a "
602 "schematic design so cannot be imported/opened in this way." ) );
603 }
604 else
605 {
606 THROW_IO_ERROR( _( "The CADSTAR schematic might be corrupt: there is no root sheet." ) );
607 }
608}
609
610
612{
613 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
614 {
615 BLOCK& block = blockPair.second;
616 LAYER_ID sheetID = "";
617
618 if( block.Type == BLOCK::TYPE::PARENT )
619 sheetID = block.LayerID;
620 else if( block.Type == BLOCK::TYPE::CHILD )
621 sheetID = block.AssocLayerID;
622 else
623 continue;
624
625 if( m_sheetMap.find( sheetID ) != m_sheetMap.end() )
626 {
627 SCH_SHEET* sheet = m_sheetMap.at( sheetID );
628
629 for( std::pair<TERMINAL_ID, TERMINAL> termPair : block.Terminals )
630 {
631 TERMINAL term = termPair.second;
632 wxString name = "YOU SHOULDN'T SEE THIS TEXT. THIS IS A BUG.";
633
634 SCH_HIERLABEL* sheetPin = nullptr;
635
636 if( block.Type == BLOCK::TYPE::PARENT )
637 sheetPin = new SCH_HIERLABEL();
638 else if( block.Type == BLOCK::TYPE::CHILD )
639 sheetPin = new SCH_SHEET_PIN( sheet );
640
641 sheetPin->SetText( name );
643 sheetPin->SetSpinStyle( getSpinStyle( term.OrientAngle, false ) );
644 sheetPin->SetPosition( getKiCadPoint( term.Position ) );
645
646 if( sheetPin->Type() == SCH_SHEET_PIN_T )
647 sheet->AddPin( (SCH_SHEET_PIN*) sheetPin );
648 else
649 sheet->GetScreen()->Append( sheetPin );
650
651 BLOCK_PIN_ID blockPinID = std::make_pair( block.ID, term.ID );
652 m_sheetPinMap.insert( { blockPinID, sheetPin } );
653 }
654 }
655 }
656}
657
658
660{
661 for( std::pair<PART_ID, PART> partPair : Parts.PartDefinitions )
662 {
663 PART_ID partID = partPair.first;
664 PART part = partPair.second;
665
666 wxString escapedPartName = EscapeString( part.Name, CTX_LIBID );
667 std::unique_ptr<LIB_SYMBOL> kiSym = std::make_unique<LIB_SYMBOL>( escapedPartName );
668
669 kiSym->SetUnitCount( part.Definition.GateSymbols.size(), true );
670 bool ok = true;
671
672 for( std::pair<GATE_ID, PART::DEFINITION::GATE> gatePair : part.Definition.GateSymbols )
673 {
674 GATE_ID gateID = gatePair.first;
675 PART::DEFINITION::GATE gate = gatePair.second;
676 SYMDEF_ID symbolID = getSymDefFromName( gate.Name, gate.Alternate );
677
678 if( symbolID.IsEmpty() )
679 {
680 m_reporter->Report( wxString::Format( _( "Part definition '%s' references symbol "
681 "'%s' (alternate '%s') which could not be "
682 "found in the symbol library. The part has "
683 "not been loaded into the KiCad library." ),
684 part.Name,
685 gate.Name,
686 gate.Alternate ),
688
689 ok = false;
690 break;
691 }
692
693 m_partSymbolsMap.insert( { { partID, gateID }, symbolID } );
694 loadSymbolGateAndPartFields( symbolID, part, gateID, kiSym.get() );
695 }
696
697 bool saveInLibrary = ok && part.Definition.GateSymbols.size() != 0;
698
699 if( !saveInLibrary )
700 {
701 if( part.Definition.GateSymbols.size() == 0 )
702 {
703 m_reporter->Report( wxString::Format( _( "Part definition '%s' has an incomplete "
704 "definition (no symbol definitions are "
705 "associated with it). The part has not "
706 "been loaded into the KiCad library." ),
707 part.Name ),
709 }
710
711 // Don't save in the library, but still keep it cached as some of the units might have
712 // been loaded correctly (saving us time later on), plus the part definition contains
713 // the part name, which is important to load
714 }
715
716 auto [partIt, inserted] = m_partMap.insert( { partID, kiSym.get() } );
717 wxCHECK2( inserted, continue );
718
719 try
720 {
721 if( saveInLibrary )
722 m_loadedSymbols.push_back( kiSym.get() );
723 }
724 catch( ... )
725 {
726 m_partMap.erase( partIt );
727 throw;
728 }
729
730 kiSym.release();
731
732 checkPoint();
733 }
734}
735
736
738{
739 for( std::pair<SYMBOL_ID, SYMBOL> symPair : Schematic.Symbols )
740 {
741 SYMBOL sym = symPair.second;
742
743 if( !sym.VariantID.empty() && sym.VariantParentSymbolID != sym.ID )
744 continue; // Only load master Variant
745
746 if( sym.IsComponent )
747 {
748 if( m_partMap.find( sym.PartRef.RefID ) == m_partMap.end() )
749 {
750 m_reporter->Report( wxString::Format( _( "Symbol '%s' references part '%s' which "
751 "could not be found in the library. The "
752 "symbol was not loaded" ),
754 sym.PartRef.RefID ),
756
757 continue;
758 }
759
760 if( sym.GateID.IsEmpty() )
761 sym.GateID = wxT( "A" ); // Assume Gate "A" if unspecified
762
763 PART_GATE_ID partSymbolID = { sym.PartRef.RefID, sym.GateID };
764 LIB_SYMBOL* kiSym = m_partMap.at( sym.PartRef.RefID );
765 std::unique_ptr<LIB_SYMBOL> kiSymCopy;
766
767 // The symbol definition in the part either does not exist for this gate number
768 // or is different to the symbol instance. We need to reload the gate for this
769 // symbol
770 if( m_partSymbolsMap.find( partSymbolID ) == m_partSymbolsMap.end()
771 || m_partSymbolsMap.at( partSymbolID ) != sym.SymdefID )
772 {
773 kiSymCopy = std::make_unique<LIB_SYMBOL>( *kiSym );
774 kiSym = kiSymCopy.get();
775 const PART& part = Parts.PartDefinitions.at( sym.PartRef.RefID );
776 loadSymbolGateAndPartFields( sym.SymdefID, part, sym.GateID, kiSym );
777 }
778
779 std::unique_ptr<LIB_SYMBOL> scaledPart(
781
782 EDA_ANGLE symOrient = ANGLE_0;
783 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, symOrient );
784
785 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
786
787 sym.ComponentRef.Designator.Replace( wxT( "\n" ), wxT( "\\n" ) );
788 sym.ComponentRef.Designator.Replace( wxT( "\r" ), wxT( "\\r" ) );
789 sym.ComponentRef.Designator.Replace( wxT( "\t" ), wxT( "\\t" ) );
790 sym.ComponentRef.Designator.Replace( wxT( " " ), wxT( "_" ) );
791
792 refField->SetText( sym.ComponentRef.Designator );
793 loadSymbolFieldAttribute( sym.ComponentRef.AttrLoc, symOrient, sym.Mirror, refField );
794
795 if( sym.HasPartRef )
796 {
797 SCH_FIELD* partField = symbol->GetField( PartNameFieldName );
798
799 if( !partField )
800 partField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, PartNameFieldName ) );
801
802 wxASSERT( partField->GetName() == PartNameFieldName );
803
804 wxString partname = getPart( sym.PartRef.RefID ).Name;
805 partname.Replace( wxT( "\n" ), wxT( "\\n" ) );
806 partname.Replace( wxT( "\r" ), wxT( "\\r" ) );
807 partname.Replace( wxT( "\t" ), wxT( "\\t" ) );
808 partField->SetText( partname );
809
810 loadSymbolFieldAttribute( sym.PartRef.AttrLoc, symOrient, sym.Mirror, partField );
811
812 partField->SetVisible( SymbolPartNameColor.IsVisible );
813 }
814
815 for( auto& attr : sym.AttributeValues )
816 {
817 ATTRIBUTE_VALUE attrVal = attr.second;
818
819 if( attrVal.HasLocation )
820 {
821 wxString attrName = getAttributeName( attrVal.AttributeID );
822 SCH_FIELD* attrField = symbol->GetField( attrName );
823
824 if( !attrField )
825 attrField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, attrName ) );
826
827 wxASSERT( attrField->GetName() == attrName );
828
829 attrVal.Value.Replace( wxT( "\n" ), wxT( "\\n" ) );
830 attrVal.Value.Replace( wxT( "\r" ), wxT( "\\r" ) );
831 attrVal.Value.Replace( wxT( "\t" ), wxT( "\\t" ) );
832 attrField->SetText( attrVal.Value );
833
834 loadSymbolFieldAttribute( attrVal.AttributeLocation, symOrient, sym.Mirror,
835 attrField );
836 attrField->SetVisible( isAttributeVisible( attrVal.AttributeID ) );
837 }
838 }
839 }
840 else if( sym.IsSymbolVariant )
841 {
842 if( Library.SymbolDefinitions.find( sym.SymdefID ) == Library.SymbolDefinitions.end() )
843 {
844 THROW_IO_ERRORF( _( "Symbol ID '%s' references library symbol '%s' which could not be found "
845 "in the library. Did you export all items of the design?" ),
846 sym.ID,
847 sym.PartRef.RefID );
848 }
849
850 SYMDEF_SCM libSymDef = Library.SymbolDefinitions.at( sym.SymdefID );
851
852 if( libSymDef.Terminals.size() != 1 )
853 {
854 THROW_IO_ERRORF( _( "Symbol ID '%s' is a signal reference or global signal but it has too "
855 "many pins. The expected number of pins is 1 but %d were found." ),
856 sym.ID,
857 libSymDef.Terminals.size() );
858 }
859
860 if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::GLOBALSIGNAL )
861 {
862 SYMDEF_ID symID = sym.SymdefID;
863 LIB_SYMBOL* kiPart = nullptr;
864
865 // In CADSTAR "GlobalSignal" is a special type of symbol which defines
866 // a Power Symbol. The "Alternate" name defines the default net name of
867 // the power symbol but this can be overridden in the design itself.
868 wxString libraryNetName = Library.SymbolDefinitions.at( symID ).Alternate;
869
870 // Name of the net that the symbol instance in CADSTAR refers to:
871 wxString symbolInstanceNetName = sym.SymbolVariant.Reference;
872 symbolInstanceNetName = EscapeString( symbolInstanceNetName, CTX_LIBID );
873
874 // Name of the symbol we will use for saving the part in KiCad
875 // Note: In CADSTAR all power symbols will start have the reference name be
876 // "GLOBALSIGNAL" followed by the default net name, so it makes sense to save
877 // the symbol in KiCad as the default net name as well.
878 wxString libPartName = libraryNetName;
879
880 // In CADSTAR power symbol instances can refer to a different net to that defined
881 // in the library. This causes problems in KiCad v6 as it breaks connectivity when
882 // the user decides to update all symbols from library. We handle this by creating
883 // individual versions of the power symbol for each net name.
884 if( libPartName != symbolInstanceNetName )
885 {
886 libPartName += wxT( " (" ) + symbolInstanceNetName + wxT( ")" );
887 }
888
889 if( m_powerSymLibMap.find( libPartName ) == m_powerSymLibMap.end() )
890 {
891 const LIB_SYMBOL* templatePart = loadSymdef( symID );
892 wxCHECK( templatePart, /*void*/ );
893
894 kiPart = new LIB_SYMBOL( *templatePart );
895 kiPart->SetGlobalPower();
896 kiPart->SetName( libPartName );
897 kiPart->GetValueField().SetText( symbolInstanceNetName );
898 kiPart->SetShowPinNames( false );
899 kiPart->SetShowPinNumbers( false );
900
901 std::vector<SCH_PIN*> pins = kiPart->GetGraphicalPins( 0, 0 );
902 wxCHECK( pins.size() == 1, /*void*/ );
903
904 pins.at( 0 )->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
905 pins.at( 0 )->SetName( symbolInstanceNetName );
906
907 if( libSymDef.TextLocations.find( SIGNALNAME_ORIGIN_ATTRID )
908 != libSymDef.TextLocations.end() )
909 {
910 TEXT_LOCATION& txtLoc =
912
913 VECTOR2I valPos = getKiCadLibraryPoint( txtLoc.Position, libSymDef.Origin );
914
915 kiPart->GetValueField().SetPosition( valPos );
916 kiPart->GetValueField().SetVisible( true );
917 }
918 else
919 {
920 kiPart->GetValueField().SetVisible( false );
921 }
922
923 kiPart->GetReferenceField().SetText( "#PWR" );
924 kiPart->GetReferenceField().SetVisible( false );
925 m_loadedSymbols.push_back( kiPart );
926 m_powerSymLibMap.insert( { libPartName, kiPart } );
927 }
928 else
929 {
930 kiPart = m_powerSymLibMap.at( libPartName );
931 wxASSERT( kiPart->GetValueField().GetText() == symbolInstanceNetName );
932 }
933
934 LIB_SYMBOL* scaledPart = getScaledLibPart( kiPart, sym.ScaleRatioNumerator,
936
937 EDA_ANGLE returnedOrient = ANGLE_0;
938 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, returnedOrient );
939 m_powerSymMap.insert( { sym.ID, symbol } );
940
941 delete scaledPart;
942 }
943 else if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::SIGNALREF )
944 {
945 // There should only be one pin and we'll use that to set the position
946 TERMINAL& symbolTerminal = libSymDef.Terminals.begin()->second;
947 VECTOR2I terminalPosOffset = symbolTerminal.Position - libSymDef.Origin;
948 EDA_ANGLE rotate = getAngle( sym.OrientAngle );
949
950 if( sym.Mirror )
951 rotate += ANGLE_180;
952
953 RotatePoint( terminalPosOffset, -rotate );
954
955 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
956 netLabel->SetPosition( getKiCadPoint( (VECTOR2I)sym.Origin + terminalPosOffset ) );
957 netLabel->SetText( "***UNKNOWN NET****" ); // This should be later updated when we load the netlist
958 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ) ) );
959
960 SYMDEF_SCM symbolDef = Library.SymbolDefinitions.at( sym.SymdefID );
961
962 if( symbolDef.TextLocations.count( LINK_ORIGIN_ATTRID ) )
963 {
964 TEXT_LOCATION linkOrigin = symbolDef.TextLocations.at( LINK_ORIGIN_ATTRID );
965 applyTextSettings( netLabel, linkOrigin.TextCodeID, linkOrigin.Alignment,
966 linkOrigin.Justification );
967 }
968
969 netLabel->SetSpinStyle( getSpinStyle( sym.OrientAngle, sym.Mirror ) );
970
971 if( libSymDef.Alternate.Lower().Contains( "in" ) )
973 else if( libSymDef.Alternate.Lower().Contains( "bi" ) )
975 else if( libSymDef.Alternate.Lower().Contains( "out" ) )
977 else
979
980 SCH_SCREEN* screen = m_sheetMap.at( sym.LayerID )->GetScreen();
981
982 // autoplace intersheet refs
983 netLabel->AutoplaceFields( screen, AUTOPLACE_AUTO );
984
985 screen->Append( netLabel );
986 m_globalLabelsMap.insert( { sym.ID, netLabel } );
987 }
988 else
989 {
990 wxASSERT_MSG( false, "Unknown Symbol Variant." );
991 }
992 }
993 else
994 {
995 m_reporter->Report( wxString::Format( _( "Symbol ID '%s' is of an unknown type. It is "
996 "neither a symbol or a net power / symbol. "
997 "The symbol was not loaded." ),
998 sym.ID ),
1000 }
1001
1002 if( sym.ScaleRatioDenominator != 1 || sym.ScaleRatioNumerator != 1 )
1003 {
1004 wxString symbolName = sym.ComponentRef.Designator;
1005
1006 if( symbolName.empty() )
1007 symbolName = wxString::Format( "ID: %s", sym.ID );
1008 else
1009 symbolName += sym.GateID;
1010
1011 m_reporter->Report( wxString::Format( _( "Symbol '%s' is scaled in the original "
1012 "CADSTAR schematic but this is not supported "
1013 "in KiCad. When the symbol is reloaded from "
1014 "the library, it will revert to the original "
1015 "1:1 scale." ),
1016 symbolName,
1017 sym.PartRef.RefID ),
1019 }
1020 }
1021}
1022
1023
1025{
1026 for( std::pair<BUS_ID, BUS> busPair : Schematic.Buses )
1027 {
1028 BUS bus = busPair.second;
1029 bool firstPt = true;
1030 VERTEX last;
1031
1032 if( bus.LayerID != wxT( "NO_SHEET" ) )
1033 {
1034 SCH_SCREEN* screen = m_sheetMap.at( bus.LayerID )->GetScreen();
1035 std::shared_ptr<BUS_ALIAS> kiBusAlias = std::make_shared<BUS_ALIAS>();
1036
1037 kiBusAlias->SetName( bus.Name );
1038 screen->AddBusAlias( kiBusAlias );
1039 m_busesMap.insert( { bus.ID, kiBusAlias } );
1040
1041 SCH_LABEL* label = new SCH_LABEL();
1042
1043 wxString busname = HandleTextOverbar( bus.Name );
1044
1045 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1046 label->SetVisible( true );
1047 screen->Append( label );
1048
1049 SHAPE_LINE_CHAIN busLineChain; // to compute nearest segment to bus label
1050
1051 for( const VERTEX& cur : bus.Shape.Vertices )
1052 {
1053 busLineChain.Append( getKiCadPoint( cur.End ) );
1054
1055 if( firstPt )
1056 {
1057 last = cur;
1058 firstPt = false;
1059
1060 if( !bus.HasBusLabel )
1061 {
1062 // Add a bus label on the starting point if the original CADSTAR design
1063 // does not have an explicit label
1064 label->SetPosition( getKiCadPoint( last.End ) );
1065 }
1066
1067 continue;
1068 }
1069
1070
1071 SCH_LINE* kiBus = new SCH_LINE();
1072
1073 kiBus->SetStartPoint( getKiCadPoint( last.End ) );
1074 kiBus->SetEndPoint( getKiCadPoint( cur.End ) );
1075 kiBus->SetLayer( LAYER_BUS );
1076 kiBus->SetLineWidth( getLineThickness( bus.LineCodeID ) );
1077 screen->Append( kiBus );
1078
1079 last = cur;
1080 }
1081
1082 if( bus.HasBusLabel )
1083 {
1084 //lets find the closest point in the busline to the label
1085 VECTOR2I busLabelLoc = getKiCadPoint( bus.BusLabel.Position );
1086 VECTOR2I nearestPt = busLineChain.NearestPoint( busLabelLoc );
1087
1088 label->SetPosition( nearestPt );
1089
1091 bus.BusLabel.Justification );
1092
1093 // Re-set bus name as it might have been "double-escaped" after applyTextSettings
1094 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1095
1096 // Note orientation of the bus label will be determined in loadNets
1097 // (the position of the wire will determine how best to place the bus label)
1098 }
1099 }
1100 }
1101}
1102
1103
1105{
1106 for( std::pair<NET_ID, NET_SCH> netPair : Schematic.Nets )
1107 {
1108 NET_SCH net = netPair.second;
1109 wxString netName = net.Name;
1110 std::map<NETELEMENT_ID, SCH_LABEL*> netlabels;
1111
1112 if( netName.IsEmpty() )
1113 netName = wxString::Format( "$%ld", net.SignalNum );
1114
1115 netName = HandleTextOverbar( netName );
1116
1117 for( std::pair<NETELEMENT_ID, NET_SCH::SYM_TERM> terminalPair : net.Terminals )
1118 {
1119 NET_SCH::SYM_TERM netTerm = terminalPair.second;
1120
1121 if( m_powerSymMap.find( netTerm.SymbolID ) != m_powerSymMap.end() )
1122 {
1123 SCH_FIELD* val = m_powerSymMap.at( netTerm.SymbolID )->GetField( FIELD_T::VALUE );
1124 val->SetText( netName );
1125 val->SetBold( false );
1126 val->SetVisible( false );
1127
1128 if( netTerm.HasNetLabel )
1129 {
1130 val->SetVisible( true );
1131 val->SetPosition( getKiCadPoint( netTerm.NetLabel.Position ) );
1132
1133 applyTextSettings( val, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1134 netTerm.NetLabel.Justification, netTerm.NetLabel.OrientAngle,
1135 netTerm.NetLabel.Mirror );
1136 }
1137 }
1138 else if( m_globalLabelsMap.find( netTerm.SymbolID ) != m_globalLabelsMap.end() )
1139 {
1140 m_globalLabelsMap.at( netTerm.SymbolID )->SetText( netName );
1141
1142 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1143
1144 if( m_sheetMap.count( sheet ) )
1145 {
1146 SCH_SCREEN* screen = m_sheetMap.at( sheet )->GetScreen();
1147
1148 // autoplace intersheet refs again since we've changed the name
1149 m_globalLabelsMap.at( netTerm.SymbolID )->AutoplaceFields( screen, AUTOPLACE_AUTO );
1150 }
1151 }
1152 else if( !net.Name.IsEmpty() && Schematic.Symbols.count( netTerm.SymbolID )
1153 && netTerm.HasNetLabel )
1154 {
1155 // This is a named net that connects to a schematic symbol pin - we need to put a label
1156 SCH_LABEL* label = new SCH_LABEL();
1157 label->SetText( netName );
1158
1159 POINT pinLocation = getLocationOfNetElement( net, netTerm.ID );
1160 label->SetPosition( getKiCadPoint( pinLocation ) );
1161 label->SetVisible( true );
1162
1163 applyTextSettings( label, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1164 netTerm.NetLabel.Justification );
1165
1166 netlabels.insert( { netTerm.ID, label } );
1167
1168 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1169 m_sheetMap.at( sheet )->GetScreen()->Append( label );
1170 }
1171 }
1172
1173 auto getHierarchicalLabel =
1174 [&]( const NETELEMENT_ID& aNode ) -> SCH_HIERLABEL*
1175 {
1176 if( aNode.Contains( "BLKT" ) )
1177 {
1178 NET_SCH::BLOCK_TERM blockTerm = net.BlockTerminals.at( aNode );
1179 BLOCK_PIN_ID blockPinID = std::make_pair( blockTerm.BlockID,
1180 blockTerm.TerminalID );
1181
1182 if( m_sheetPinMap.find( blockPinID ) != m_sheetPinMap.end() )
1183 return m_sheetPinMap.at( blockPinID );
1184 }
1185
1186 return nullptr;
1187 };
1188
1189 //Add net name to all hierarchical pins (block terminals in CADSTAR)
1190 for( std::pair<NETELEMENT_ID, NET_SCH::BLOCK_TERM> blockPair : net.BlockTerminals )
1191 {
1192 SCH_HIERLABEL* label = getHierarchicalLabel( blockPair.first );
1193
1194 if( label )
1195 label->SetText( netName );
1196 }
1197
1198 // Load all bus entries and add net label if required
1199 for( std::pair<NETELEMENT_ID, NET_SCH::BUS_TERM> busPair : net.BusTerminals )
1200 {
1201 NET_SCH::BUS_TERM busTerm = busPair.second;
1202 BUS bus = Schematic.Buses.at( busTerm.BusID );
1203
1204 if( !alg::contains( m_busesMap.at( bus.ID )->Members(), netName ) )
1205 m_busesMap.at( bus.ID )->AddMember( netName );
1206
1207 SCH_BUS_WIRE_ENTRY* busEntry =
1208 new SCH_BUS_WIRE_ENTRY( getKiCadPoint( busTerm.FirstPoint ), false );
1209
1210 VECTOR2I size =
1211 getKiCadPoint( busTerm.SecondPoint ) - getKiCadPoint( busTerm.FirstPoint );
1212 busEntry->SetSize( VECTOR2I( size.x, size.y ) );
1213
1214 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( busEntry );
1215
1216 // Always add a label at bus terminals to ensure connectivity.
1217 // If the original design does not have a label, just make it very small
1218 // to keep connectivity but make the design look visually similar to
1219 // the original.
1220 SCH_LABEL* label = new SCH_LABEL();
1221 label->SetText( netName );
1222 label->SetPosition( getKiCadPoint( busTerm.SecondPoint ) );
1223 label->SetVisible( true );
1224
1225 if( busTerm.HasNetLabel )
1226 {
1227 applyTextSettings( label, busTerm.NetLabel.TextCodeID, busTerm.NetLabel.Alignment,
1228 busTerm.NetLabel.Justification );
1229 }
1230 else
1231 {
1233 }
1234
1235 netlabels.insert( { busTerm.ID, label } );
1236 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( label );
1237 }
1238
1239 for( std::pair<NETELEMENT_ID, NET_SCH::DANGLER> danglerPair : net.Danglers )
1240 {
1241 NET_SCH::DANGLER dangler = danglerPair.second;
1242
1243 SCH_LABEL* label = new SCH_LABEL();
1244 label->SetPosition( getKiCadPoint( dangler.Position ) );
1245 label->SetVisible( true );
1246
1247 if( dangler.HasNetLabel )
1248 {
1249 applyTextSettings( label, dangler.NetLabel.TextCodeID, dangler.NetLabel.Alignment,
1250 dangler.NetLabel.Justification );
1251 }
1252
1253 label->SetText( netName ); // set text after applying settings to avoid double-escaping
1254 netlabels.insert( { dangler.ID, label } );
1255
1256 m_sheetMap.at( dangler.LayerID )->GetScreen()->Append( label );
1257 }
1258
1259 for( NET_SCH::CONNECTION_SCH conn : net.Connections )
1260 {
1261 if( conn.LayerID == wxT( "NO_SHEET" ) )
1262 continue; // No point loading virtual connections. KiCad handles that internally
1263
1264 POINT start = getLocationOfNetElement( net, conn.StartNode );
1265 POINT end = getLocationOfNetElement( net, conn.EndNode );
1266
1267 if( start.x == UNDEFINED_VALUE || end.x == UNDEFINED_VALUE )
1268 continue;
1269
1270 // Connections in CADSTAR are always implied between symbols even if the route
1271 // doesn't start and end exactly at the connection points
1272 if( conn.Path.size() < 1 || conn.Path.front().End != start )
1273 conn.Path.insert( conn.Path.begin(), VERTEX( VERTEX_TYPE::VT_POINT, start ) );
1274
1275 if( conn.Path.size() < 2 || conn.Path.back().End != end )
1276 conn.Path.push_back( VERTEX( VERTEX_TYPE::VT_POINT, end ) );
1277
1278 bool firstPt = true;
1279 bool secondPt = false;
1280 VECTOR2I last;
1281 SCH_LINE* wire = nullptr;
1282
1283 SHAPE_LINE_CHAIN wireChain; // Create a temp. line chain representing the connection
1284
1285 auto cadstarToKicadPoint = [this]( const VECTOR2I& aPoint ) -> VECTOR2I
1286 {
1287 return getKiCadPoint( aPoint );
1288 };
1289
1290 for( const VERTEX& vertex : conn.Path )
1291 vertex.AppendToChain( &wireChain, cadstarToKicadPoint, ARC_ACCURACY );
1292
1293 // AUTO-FIX SHEET PINS
1294 //--------------------
1295 // KiCad constrains the sheet pin on the edge of the sheet object whereas in
1296 // CADSTAR it can be anywhere. Let's find the intersection of the wires with the sheet
1297 // and place the hierarchical
1298 std::vector<NETELEMENT_ID> nodes;
1299 nodes.push_back( conn.StartNode );
1300 nodes.push_back( conn.EndNode );
1301
1302 for( const NETELEMENT_ID& node : nodes )
1303 {
1304 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( node );
1305
1306 if( sheetPin )
1307 {
1308 if( sheetPin->Type() == SCH_SHEET_PIN_T
1309 && SCH_SHEET::ClassOf( sheetPin->GetParent() ) )
1310 {
1311 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( sheetPin->GetParent() );
1312 VECTOR2I sheetSize = parentSheet->GetSize();
1313 VECTOR2I sheetPosition = parentSheet->GetPosition();
1314
1315 int leftSide = sheetPosition.x;
1316 int rightSide = sheetPosition.x + sheetSize.x;
1317 int topSide = sheetPosition.y;
1318 int botSide = sheetPosition.y + sheetSize.y;
1319
1320 SHAPE_LINE_CHAIN sheetEdge;
1321
1322 sheetEdge.Append( leftSide, topSide );
1323 sheetEdge.Append( rightSide, topSide );
1324 sheetEdge.Append( rightSide, botSide );
1325 sheetEdge.Append( leftSide, botSide );
1326 sheetEdge.Append( leftSide, topSide );
1327
1328 SHAPE_LINE_CHAIN::INTERSECTIONS wireToSheetIntersects;
1329
1330 if( !wireChain.Intersect( sheetEdge, wireToSheetIntersects ) )
1331 {
1332 // The block terminal is outside the block shape in the original
1333 // CADSTAR design. Since KiCad's Sheet Pin will already be constrained
1334 // on the edge, we will simply join to it with a straight line.
1335 if( node == conn.StartNode )
1336 wireChain = wireChain.Reverse();
1337
1338 wireChain.Append( sheetPin->GetPosition() );
1339
1340 if( node == conn.StartNode )
1341 wireChain = wireChain.Reverse();
1342 }
1343 else
1344 {
1345 // The block terminal is either inside or on the shape edge. Lets use
1346 // the first intersection point.
1347 VECTOR2I intsctPt = wireToSheetIntersects.at( 0 ).p;
1348 int intsctIndx = wireChain.FindSegment( intsctPt );
1349 wxASSERT_MSG( intsctIndx != -1, "Can't find intersecting segment" );
1350
1351 if( node == conn.StartNode )
1352 wireChain.Replace( 0, intsctIndx, intsctPt );
1353 else
1354 wireChain.Replace( intsctIndx + 1, /*end index*/ -1, intsctPt );
1355
1356 sheetPin->SetPosition( intsctPt );
1357 }
1358 }
1359 }
1360 }
1361
1362 auto fixNetLabelsAndSheetPins =
1363 [&]( const EDA_ANGLE& aWireAngle, NETELEMENT_ID& aNetEleID )
1364 {
1365 SPIN_STYLE spin = getSpinStyle( aWireAngle );
1366
1367 if( netlabels.find( aNetEleID ) != netlabels.end() )
1368 netlabels.at( aNetEleID )->SetSpinStyle( spin.MirrorY() );
1369
1370 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( aNetEleID );
1371
1372 if( sheetPin )
1373 sheetPin->SetSpinStyle( spin.MirrorX() );
1374 };
1375
1376 // Now we can load the wires and fix the label orientations
1377 for( const VECTOR2I& pt : wireChain.CPoints() )
1378 {
1379 if( firstPt )
1380 {
1381 last = pt;
1382 firstPt = false;
1383 secondPt = true;
1384 continue;
1385 }
1386
1387 if( secondPt )
1388 {
1389 secondPt = false;
1390
1391 EDA_ANGLE wireAngle( last - pt );
1392 fixNetLabelsAndSheetPins( wireAngle, conn.StartNode );
1393 }
1394
1395 wire = new SCH_LINE();
1396
1397 wire->SetStartPoint( last );
1398 wire->SetEndPoint( pt );
1399 wire->SetLayer( LAYER_WIRE );
1400
1401 if( !conn.ConnectionLineCode.IsEmpty() )
1402 wire->SetLineWidth( getLineThickness( conn.ConnectionLineCode ) );
1403
1404 last = pt;
1405
1406 m_sheetMap.at( conn.LayerID )->GetScreen()->Append( wire );
1407 }
1408
1409 //Fix labels on the end wire
1410 if( wire )
1411 {
1412 EDA_ANGLE wireAngle( wire->GetEndPoint() - wire->GetStartPoint() );
1413 fixNetLabelsAndSheetPins( wireAngle, conn.EndNode );
1414 }
1415 }
1416
1417 for( std::pair<NETELEMENT_ID, NET_SCH::JUNCTION_SCH> juncPair : net.Junctions )
1418 {
1419 NET_SCH::JUNCTION_SCH junc = juncPair.second;
1420
1421 SCH_JUNCTION* kiJunc = new SCH_JUNCTION();
1422
1423 kiJunc->SetPosition( getKiCadPoint( junc.Location ) );
1424 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( kiJunc );
1425
1426 if( junc.HasNetLabel )
1427 {
1428 // In CADSTAR the label can be placed anywhere, but in KiCad it has to be placed
1429 // in the same location as the junction for it to be connected to it.
1430 SCH_LABEL* label = new SCH_LABEL();
1431 label->SetText( netName );
1432 label->SetPosition( getKiCadPoint( junc.Location ) );
1433 label->SetVisible( true );
1434
1435 EDA_ANGLE labelAngle = getAngle( junc.NetLabel.OrientAngle );
1436 SPIN_STYLE spin = getSpinStyle( labelAngle );
1437
1438 label->SetSpinStyle( spin );
1439
1440 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( label );
1441 }
1442 }
1443 }
1444}
1445
1446
1448{
1449 for( std::pair<FIGURE_ID, FIGURE> figPair : Schematic.Figures )
1450 {
1451 FIGURE fig = figPair.second;
1452
1453 loadFigure( fig, fig.LayerID, LAYER_NOTES );
1454 }
1455}
1456
1457
1459{
1460 for( std::pair<TEXT_ID, TEXT> textPair : Schematic.Texts )
1461 {
1462 TEXT txt = textPair.second;
1463
1464 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1465 loadItemOntoKiCadSheet( txt.LayerID, kiTxt );
1466 }
1467}
1468
1469
1471{
1472 for( std::pair<DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL> docSymPair :
1473 Schematic.DocumentationSymbols )
1474 {
1475 DOCUMENTATION_SYMBOL docSym = docSymPair.second;
1476
1477 if( Library.SymbolDefinitions.find( docSym.SymdefID ) == Library.SymbolDefinitions.end() )
1478 {
1479 m_reporter->Report( wxString::Format( _( "Documentation Symbol '%s' refers to symbol "
1480 "definition ID '%s' which does not exist in "
1481 "the library. The symbol was not loaded." ),
1482 docSym.ID,
1483 docSym.SymdefID ),
1485 continue;
1486 }
1487
1488 SYMDEF_SCM docSymDef = Library.SymbolDefinitions.at( docSym.SymdefID );
1489 VECTOR2I moveVector = getKiCadPoint( docSym.Origin ) - getKiCadPoint( docSymDef.Origin );
1490 EDA_ANGLE rotationAngle = getAngle( docSym.OrientAngle );
1491 double scalingFactor = (double) docSym.ScaleRatioNumerator
1492 / (double) docSym.ScaleRatioDenominator;
1493 VECTOR2I centreOfTransform = getKiCadPoint( docSymDef.Origin );
1494 bool mirrorInvert = docSym.Mirror;
1495
1496 for( std::pair<FIGURE_ID, FIGURE> figPair : docSymDef.Figures )
1497 {
1498 FIGURE fig = figPair.second;
1499
1500 loadFigure( fig, docSym.LayerID, LAYER_NOTES, moveVector, rotationAngle, scalingFactor,
1501 centreOfTransform, mirrorInvert );
1502 }
1503
1504 for( std::pair<TEXT_ID, TEXT> textPair : docSymDef.Texts )
1505 {
1506 TEXT txt = textPair.second;
1507
1508 txt.Mirror = ( txt.Mirror ) ? !mirrorInvert : mirrorInvert;
1509 txt.OrientAngle = docSym.OrientAngle - txt.OrientAngle;
1510
1511 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1512
1513 VECTOR2I newPosition = applyTransform( kiTxt->GetPosition(), moveVector, rotationAngle,
1514 scalingFactor, centreOfTransform, mirrorInvert );
1515
1516 int newTxtWidth = KiROUND( kiTxt->GetTextWidth() * scalingFactor );
1517 int newTxtHeight = KiROUND( kiTxt->GetTextHeight() * scalingFactor );
1518 int newTxtThickness = KiROUND( kiTxt->GetTextThickness() * scalingFactor );
1519
1520 kiTxt->SetPosition( newPosition );
1521 kiTxt->SetTextWidth( newTxtWidth );
1522 kiTxt->SetTextHeight( newTxtHeight );
1523 kiTxt->SetTextThickness( newTxtThickness );
1524
1525 loadItemOntoKiCadSheet( docSym.LayerID, kiTxt );
1526 }
1527 }
1528}
1529
1530
1532{
1533 auto findAndReplaceTextField =
1534 [&]( TEXT_FIELD_NAME aField, wxString aValue )
1535 {
1536 if( m_context.TextFieldToValuesMap.find( aField ) != m_context.TextFieldToValuesMap.end() )
1537 {
1538 if( m_context.TextFieldToValuesMap.at( aField ) != aValue )
1539 {
1540 m_context.TextFieldToValuesMap.at( aField ) = aValue;
1541 m_context.InconsistentTextFields.insert( aField );
1542 return false;
1543 }
1544 }
1545 else
1546 {
1547 m_context.TextFieldToValuesMap.insert( { aField, aValue } );
1548 }
1549
1550 return true;
1551 };
1552
1553 PROJECT* pj = &m_schematic->Project();
1554
1555 if( pj )
1556 {
1557 std::map<wxString, wxString>& txtVars = pj->GetTextVars();
1558
1559 // Most of the design text fields can be derived from other elements
1560 if( Schematic.VariantHierarchy.Variants.size() > 0 )
1561 {
1562 VARIANT loadedVar = Schematic.VariantHierarchy.Variants.begin()->second;
1563
1564 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_NAME, loadedVar.Name );
1565 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_DESCRIPTION, loadedVar.Description );
1566 }
1567
1568 findAndReplaceTextField( TEXT_FIELD_NAME::DESIGN_TITLE, Header.JobTitle );
1569
1570 for( std::pair<TEXT_FIELD_NAME, wxString> txtvalue : m_context.TextFieldToValuesMap )
1571 {
1572 wxString varName = CADSTAR_TO_KICAD_FIELDS.at( txtvalue.first );
1573 wxString varValue = txtvalue.second;
1574
1575 txtVars.insert( { varName, varValue } );
1576 }
1577
1578 for( std::pair<wxString, wxString> txtvalue : m_context.FilenamesToTextMap )
1579 {
1580 wxString varName = txtvalue.first;
1581 wxString varValue = txtvalue.second;
1582
1583 txtVars.insert( { varName, varValue } );
1584 }
1585 }
1586 else
1587 {
1588 m_reporter->Report( _( "Text Variables could not be set as there is no project attached." ),
1590 }
1591}
1592
1593
1595 LIB_SYMBOL* aKiCadSymbol )
1596{
1597 // First Check if field already exists
1598 if( SCH_FIELD* existingField = aKiCadSymbol->GetField( aFieldName ) )
1599 return existingField;
1600
1601 SCH_FIELD* newfield = new SCH_FIELD( aKiCadSymbol, FIELD_T::USER, aFieldName );
1602 newfield->SetVisible( false );
1603 aKiCadSymbol->AddField( newfield );
1604 /*
1605 @todo we should load that a field is a URL by checking if it starts with "Link"
1606 e.g.:
1607 if( aFieldName.Lower().StartsWith( "link" ) )
1608 newfield->SetAsURL*/
1609
1610 return newfield;
1611}
1612
1613
1615{
1616 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), nullptr );
1617
1618 if( m_symDefMap.count( aSymdefID ) )
1619 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1620
1621 SYMDEF_SCM csSym = Library.SymbolDefinitions.at( aSymdefID );
1622 std::unique_ptr<LIB_SYMBOL> kiSym = std::make_unique<LIB_SYMBOL>( csSym.BuildLibName() );
1623 const int gateNumber = 1; // Always load to gate "A" - we will change the unit later
1624
1625 // Load Graphical Figures
1626 for( std::pair<FIGURE_ID, FIGURE> figPair : csSym.Figures )
1627 {
1628 FIGURE fig = figPair.second;
1629 int lineThickness = getLineThickness( fig.LineCodeID );
1630 LINE_STYLE linestyle = getLineStyle( fig.LineCodeID );
1631
1632 if( fig.Shape.Type == SHAPE_TYPE::OPENSHAPE )
1633 {
1634 loadLibrarySymbolShapeVertices( fig.Shape.Vertices, csSym.Origin, kiSym.get(),
1635 gateNumber,
1636 lineThickness );
1637 }
1638 else
1639 {
1641
1643 [&]( const VECTOR2I& aPt )
1644 {
1645 return getKiCadLibraryPoint( aPt, csSym.Origin );
1646 },
1647 ARC_ACCURACY ) );
1648
1649 shape->SetUnit( gateNumber );
1650
1651 shape->SetStroke( STROKE_PARAMS( lineThickness, linestyle ) );
1652
1653 if( fig.Shape.Type == SHAPE_TYPE::SOLID )
1655 else if( fig.Shape.Type == SHAPE_TYPE::OUTLINE )
1656 shape->SetFillMode( FILL_T::NO_FILL );
1657 else if( fig.Shape.Type == SHAPE_TYPE::HATCHED ) // We don't have an equivalent
1659
1660 kiSym->AddDrawItem( shape );
1661 }
1662 }
1663
1664 PINNUM_TO_TERMINAL_MAP pinNumToTerminals;
1665
1666 // Load Pins
1667 for( std::pair<TERMINAL_ID, TERMINAL> termPair : csSym.Terminals )
1668 {
1669 TERMINAL term = termPair.second;
1670 wxString pinNum = wxString::Format( "%ld", term.ID );
1671 wxString pinName = wxEmptyString;
1672 std::unique_ptr<SCH_PIN> pin = std::make_unique<SCH_PIN>( kiSym.get() );
1673
1674 // Assume passive pin for now (we will set it later once we load the parts)
1676
1677 pin->SetPosition( getKiCadLibraryPoint( term.Position, csSym.Origin ) );
1678 pin->SetLength( 0 ); //CADSTAR Pins are just a point (have no length)
1679 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
1680 pin->SetUnit( gateNumber );
1681 pin->SetNumber( pinNum );
1682 pin->SetName( pinName );
1683
1684 // TC0 is the default CADSTAR text size for name/number if none specified
1685 int pinNumberHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1686 int pinNameHeight = getTextHeightFromTextCode( wxT( "TC0" ) );
1687
1688 if( csSym.PinNumberLocations.count( term.ID ) )
1689 {
1690 PIN_NUM_LABEL_LOC pinNumLocation = csSym.PinNumberLocations.at( term.ID );
1691 pinNumberHeight = getTextHeightFromTextCode( pinNumLocation.TextCodeID );
1692 }
1693
1694 if( csSym.PinLabelLocations.count( term.ID ) )
1695 {
1696 PIN_NUM_LABEL_LOC pinNameLocation = csSym.PinLabelLocations.at( term.ID );
1697 pinNameHeight = getTextHeightFromTextCode( pinNameLocation.TextCodeID );
1698 }
1699
1700 pin->SetNumberTextSize( pinNumberHeight );
1701 pin->SetNameTextSize( pinNameHeight );
1702
1703 pinNumToTerminals.insert( { pin->GetNumber(), term.ID } );
1704 kiSym->AddDrawItem( pin.release() );
1705 }
1706
1707 m_symDefTerminalsMap.insert( { aSymdefID, pinNumToTerminals } );
1708 fixUpLibraryPins( kiSym.get(), gateNumber );
1709
1710
1711 // Load Text items
1712 for( std::pair<TEXT_ID, TEXT> textPair : csSym.Texts )
1713 {
1714 TEXT csText = textPair.second;
1715 VECTOR2I pos = getKiCadLibraryPoint( csText.Position, csSym.Origin );
1716 auto libtext = std::make_unique<SCH_TEXT>( pos, csText.Text, LAYER_DEVICE );
1717
1718 libtext->SetUnit( gateNumber );
1719 libtext->SetPosition( getKiCadLibraryPoint( csText.Position, csSym.Origin ) );
1720 libtext->SetMultilineAllowed( true ); // temporarily so that we calculate bbox correctly
1721
1722 applyTextSettings( libtext.get(), csText.TextCodeID, csText.Alignment, csText.Justification,
1723 csText.OrientAngle, csText.Mirror );
1724
1725 // Split out multi line text items into individual text elements
1726 if( csText.Text.Contains( "\n" ) )
1727 {
1728 wxArrayString strings;
1729 wxStringSplit( csText.Text, strings, '\n' );
1730
1731 for( size_t ii = 0; ii < strings.size(); ++ii )
1732 {
1733 BOX2I bbox = libtext->GetTextBox( nullptr, ii );
1734 VECTOR2I linePos = { bbox.GetLeft(), -bbox.GetBottom() };
1735
1736 RotatePoint( linePos, libtext->GetTextPos(), -libtext->GetTextAngle() );
1737
1738 SCH_TEXT* textLine = static_cast<SCH_TEXT*>( libtext->Duplicate( IGNORE_PARENT_GROUP ) );
1739 textLine->SetText( strings[ii] );
1742 textLine->SetTextPos( linePos );
1743
1744 // Multiline text not allowed in LIB_TEXT
1745 textLine->SetMultilineAllowed( false );
1746 kiSym->AddDrawItem( textLine );
1747 }
1748 }
1749 else
1750 {
1751 // Multiline text not allowed in LIB_TEXT
1752 libtext->SetMultilineAllowed( false );
1753 kiSym->AddDrawItem( libtext.release() );
1754 }
1755 }
1756
1757 // CADSTAR uses TC1 when fields don't have explicit text/attribute location
1758 static const TEXTCODE_ID defaultTextCode = "TC1";
1759
1760 // Load field locations (Attributes in CADSTAR)
1761
1762 // Symbol name (e.g. R1)
1763 if( csSym.TextLocations.count( SYMBOL_NAME_ATTRID ) )
1764 {
1765 TEXT_LOCATION& textLoc = csSym.TextLocations.at( SYMBOL_NAME_ATTRID );
1766 applyToLibraryFieldAttribute( textLoc, csSym.Origin, &kiSym->GetReferenceField() );
1767 }
1768 else
1769 {
1770 applyTextCodeIfExists( &kiSym->GetReferenceField(), defaultTextCode );
1771 }
1772
1773 // Always add the part name field (even if it doesn't have a specific location defined)
1774 SCH_FIELD* partField = addNewFieldToSymbol( PartNameFieldName, kiSym.get() );
1775 wxCHECK( partField, nullptr );
1776 wxASSERT( partField->GetName() == PartNameFieldName );
1777
1778 if( csSym.TextLocations.count( PART_NAME_ATTRID ) )
1779 {
1780 TEXT_LOCATION& textLoc = csSym.TextLocations.at( PART_NAME_ATTRID );
1781 applyToLibraryFieldAttribute( textLoc, csSym.Origin, partField );
1782 }
1783 else
1784 {
1785 applyTextCodeIfExists( partField, defaultTextCode );
1786 }
1787
1788 partField->SetVisible( SymbolPartNameColor.IsVisible );
1789
1790
1791 for( auto& [attributeId, textLocation] : csSym.TextLocations )
1792 {
1793 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1794 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1795 {
1796 continue;
1797 }
1798
1799 wxString attributeName = getAttributeName( attributeId );
1800 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym.get() );
1801 applyToLibraryFieldAttribute( textLocation, csSym.Origin, field );
1802 }
1803
1804
1805 for( auto& [attributeId, attrValue] : csSym.AttributeValues )
1806 {
1807 if( attributeId == PART_NAME_ATTRID || attributeId == SYMBOL_NAME_ATTRID
1808 || attributeId == SIGNALNAME_ORIGIN_ATTRID || attributeId == LINK_ORIGIN_ATTRID )
1809 {
1810 continue;
1811 }
1812
1813 wxString attributeName = getAttributeName( attributeId );
1814 SCH_FIELD* field = addNewFieldToSymbol( attributeName, kiSym.get() );
1815
1816 if( attrValue.HasLocation )
1817 applyToLibraryFieldAttribute( attrValue.AttributeLocation, csSym.Origin, field );
1818 else
1819 applyTextCodeIfExists( field, defaultTextCode );
1820 }
1821
1822
1823 m_symDefMap.insert( { aSymdefID, std::move( kiSym ) } );
1824
1825 return m_symDefMap.at( aSymdefID ).get(); // return a non-owning ptr
1826}
1827
1828
1830 const PART& aCadstarPart,
1831 const GATE_ID& aGateID,
1832 LIB_SYMBOL* aSymbol )
1833{
1834 wxCHECK( Library.SymbolDefinitions.find( aSymdefID ) != Library.SymbolDefinitions.end(), /*void*/ );
1835
1836 std::unique_ptr<LIB_SYMBOL> kiSymDef( loadSymdef( aSymdefID )->Duplicate() );
1837 wxCHECK( kiSymDef, /*void*/ );
1838
1839 // Update the pin numbers to match those defined in the Cadstar part
1840 TERMINAL_TO_PINNUM_MAP pinNumMap;
1841
1842 for( auto&& [storedPinNum, termID] : m_symDefTerminalsMap[aSymdefID] )
1843 {
1844 PART::DEFINITION::PIN csPin = getPartDefinitionPin( aCadstarPart, aGateID, termID );
1845 std::vector<SCH_PIN*> pins = kiSymDef->GetPinsByNumber( storedPinNum );
1846
1847 wxString pinName = HandleTextOverbar( csPin.Label );
1848 wxString pinNum = HandleTextOverbar( csPin.Name );
1849
1850 if( pinNum.IsEmpty() )
1851 {
1852 if( !csPin.Identifier.IsEmpty() )
1853 pinNum = csPin.Identifier;
1854 else if( csPin.ID == UNDEFINED_VALUE )
1855 pinNum = wxString::Format( "%ld", termID );
1856 else
1857 pinNum = wxString::Format( "%ld", csPin.ID );
1858 }
1859
1860 for( SCH_PIN* pin : pins )
1861 {
1862 pin->SetType( getKiCadPinType( csPin.Type ) );
1863 pin->SetNumber( pinNum );
1864 pin->SetName( pinName );
1865 }
1866
1867 pinNumMap.insert( { termID, pinNum } );
1868 }
1869
1870 m_pinNumsMap.insert( { aCadstarPart.ID + aGateID, pinNumMap } );
1871
1872 // COPY ITEMS
1873 int gateNumber = getKiCadUnitNumberFromGate( aGateID );
1874 copySymbolItems( kiSymDef.get(), aSymbol, gateNumber );
1875
1876 // Hide the value field for now (it might get unhidden if an attribute exists in the cadstar
1877 // design with the text "Value"
1878 aSymbol->GetValueField().SetVisible( false );
1879
1880
1881 if( SCH_FIELD* partNameField = aSymbol->GetField( PartNameFieldName ) )
1882 partNameField->SetText( EscapeFieldText( aCadstarPart.Name ) );
1883
1884 const POINT& symDefOrigin = Library.SymbolDefinitions.at( aSymdefID ).Origin;
1885 wxString footprintRefName = wxEmptyString;
1886 wxString footprintAlternateName = wxEmptyString;
1887
1888 auto loadLibraryField = [&]( const ATTRIBUTE_VALUE& aAttributeVal )
1889 {
1890 wxString attrName = getAttributeName( aAttributeVal.AttributeID );
1891
1892 // Remove invalid field characters
1893 wxString attributeValue = aAttributeVal.Value;
1894 attributeValue.Replace( wxT( "\n" ), wxT( "\\n" ) );
1895 attributeValue.Replace( wxT( "\r" ), wxT( "\\r" ) );
1896 attributeValue.Replace( wxT( "\t" ), wxT( "\\t" ) );
1897
1898 //TODO: Handle "links": In cadstar a field can be a "link" if its name starts
1899 // with the characters "Link ". Need to figure out how to convert them to
1900 // equivalent in KiCad.
1901
1902 if( attrName == wxT( "(PartDefinitionNameStem)" ) )
1903 {
1904 //Space not allowed in Reference field
1905 attributeValue.Replace( wxT( " " ), "_" );
1906 aSymbol->GetReferenceField().SetText( attributeValue );
1907 return;
1908 }
1909 else if( attrName == wxT( "(PartDescription)" ) )
1910 {
1911 aSymbol->SetDescription( attributeValue );
1912 return;
1913 }
1914 else if( attrName == wxT( "(PartDefinitionReferenceName)" ) )
1915 {
1916 footprintRefName = attributeValue;
1917 return;
1918 }
1919 else if( attrName == wxT( "(PartDefinitionAlternateName)" ) )
1920 {
1921 footprintAlternateName = attributeValue;
1922 return;
1923 }
1924
1925 bool attrIsNew = aSymbol->GetField( attrName ) == nullptr;
1926 SCH_FIELD* attrField = addNewFieldToSymbol( attrName, aSymbol );
1927
1928 wxASSERT( attrField->GetName() == attrName );
1929 attrField->SetText( aAttributeVal.Value );
1930 attrField->SetUnit( gateNumber );
1931
1932 const ATTRIBUTE_ID& attrid = aAttributeVal.AttributeID;
1933 attrField->SetVisible( isAttributeVisible( attrid ) );
1934
1935 if( aAttributeVal.HasLocation )
1936 {
1937 // Check if the part itself defined a location for the field
1938 applyToLibraryFieldAttribute( aAttributeVal.AttributeLocation, symDefOrigin,
1939 attrField );
1940 }
1941 else if( attrIsNew )
1942 {
1943 attrField->SetVisible( false );
1944 applyTextSettings( attrField, wxT( "TC1" ), ALIGNMENT::NO_ALIGNMENT,
1945 JUSTIFICATION::LEFT, false, true );
1946 }
1947 };
1948
1949 // Load all attributes in the Part Definition
1950 for( auto& [attrId, attrVal] : aCadstarPart.Definition.AttributeValues )
1951 loadLibraryField( attrVal );
1952
1953 // Load all attributes in the Part itself.
1954 for( auto& [attrId, attrVal] : aCadstarPart.AttributeValues )
1955 loadLibraryField( attrVal );
1956
1957 setFootprintOnSymbol( aSymbol, footprintRefName, footprintAlternateName );
1958
1959 if( aCadstarPart.Definition.HidePinNames )
1960 {
1961 aSymbol->SetShowPinNames( false );
1962 aSymbol->SetShowPinNumbers( false );
1963 }
1964}
1965
1966
1968 const wxString& aFootprintName,
1969 const wxString& aFootprintAlternate )
1970{
1971 wxString fpNameInLibrary = generateLibName( aFootprintName, aFootprintAlternate );
1972
1973 if( !fpNameInLibrary.IsEmpty() )
1974 {
1975 wxArrayString fpFilters;
1976 fpFilters.Add( aFootprintName ); // In cadstar one footprint has several "alternates"
1977
1978 if( !aFootprintAlternate.IsEmpty() )
1979 fpFilters.Add( fpNameInLibrary );
1980
1981 aKiCadSymbol->SetFPFilters( fpFilters );
1982
1983 LIB_ID libID( m_footprintLibName, fpNameInLibrary );
1984 aKiCadSymbol->GetFootprintField().SetText( libID.Format() );
1985 }
1986}
1987
1988
1989void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
1990 const VECTOR2I& aSymbolOrigin,
1991 LIB_SYMBOL* aSymbol,
1992 int aGateNumber,
1993 int aLineThickness )
1994{
1995 const VERTEX* prev = &aCadstarVertices.at( 0 );
1996 const VERTEX* cur;
1997
1998 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT, "First vertex should always be a point." );
1999
2000 for( size_t i = 1; i < aCadstarVertices.size(); i++ )
2001 {
2002 cur = &aCadstarVertices.at( i );
2003
2004 SCH_SHAPE* shape = nullptr;
2005 bool cw = false;
2006 VECTOR2I startPoint = getKiCadLibraryPoint( prev->End, aSymbolOrigin );
2007 VECTOR2I endPoint = getKiCadLibraryPoint( cur->End, aSymbolOrigin );
2008 VECTOR2I centerPoint;
2009
2012 {
2013 centerPoint = ( startPoint + endPoint ) / 2;
2014 }
2015 else
2016 {
2017 centerPoint = getKiCadLibraryPoint( cur->Center, aSymbolOrigin );
2018 }
2019
2020
2021 switch( cur->Type )
2022 {
2024 shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2025 shape->AddPoint( startPoint );
2026 shape->AddPoint( endPoint );
2027 break;
2028
2031 cw = true;
2033
2036 shape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2037
2038 shape->SetPosition( centerPoint );
2039
2040 if( cw )
2041 {
2042 shape->SetStart( endPoint );
2043 shape->SetEnd( startPoint );
2044 }
2045 else
2046 {
2047 shape->SetStart( startPoint );
2048 shape->SetEnd( endPoint );
2049 }
2050
2051 break;
2052 }
2053
2054 shape->SetUnit( aGateNumber );
2055 shape->SetStroke( STROKE_PARAMS( aLineThickness, LINE_STYLE::SOLID ) );
2056 aSymbol->AddDrawItem( shape, false );
2057
2058 prev = cur;
2059 }
2060
2061 aSymbol->GetDrawItems().sort();
2062}
2063
2064
2066 const VECTOR2I& aSymbolOrigin,
2067 SCH_FIELD* aKiCadField )
2068{
2069 aKiCadField->SetTextPos( getKiCadLibraryPoint( aCadstarAttrLoc.Position, aSymbolOrigin ) );
2070
2071 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, aCadstarAttrLoc.Alignment,
2072 aCadstarAttrLoc.Justification, aCadstarAttrLoc.OrientAngle,
2073 aCadstarAttrLoc.Mirror );
2074}
2075
2076
2078 const LIB_SYMBOL& aKiCadPart,
2079 EDA_ANGLE& aComponentOrientation )
2080{
2081 wxString libName = CreateLibName( m_footprintLibName, m_rootSheet );
2082
2083 LIB_ID libId;
2084 libId.SetLibItemName( aKiCadPart.GetName() );
2085 libId.SetLibNickname( libName );
2086
2087 int unit = getKiCadUnitNumberFromGate( aCadstarSymbol.GateID );
2088
2089 SCH_SHEET_PATH sheetpath;
2090 SCH_SHEET* kiSheet = m_sheetMap.at( aCadstarSymbol.LayerID );
2091 m_rootSheet->LocatePathOfScreen( kiSheet->GetScreen(), &sheetpath );
2092
2093 SCH_SYMBOL* symbol = new SCH_SYMBOL( aKiCadPart, libId, &sheetpath, unit );
2094
2095 if( aCadstarSymbol.IsComponent )
2096 symbol->SetRef( &sheetpath, aCadstarSymbol.ComponentRef.Designator );
2097
2098 symbol->SetPosition( getKiCadPoint( aCadstarSymbol.Origin ) );
2099
2100 EDA_ANGLE compAngle = getAngle( aCadstarSymbol.OrientAngle );
2101 int compOrientation = 0;
2102
2103 if( aCadstarSymbol.Mirror )
2104 {
2105 compAngle = -compAngle;
2106 compOrientation += SYMBOL_ORIENTATION_T::SYM_MIRROR_Y;
2107 }
2108
2109 compOrientation += getComponentOrientation( compAngle, aComponentOrientation );
2110 EDA_ANGLE test1( compAngle );
2111 EDA_ANGLE test2( aComponentOrientation );
2112
2113 if( test1.Normalize180() != test2.Normalize180() )
2114 {
2115 m_reporter->Report( wxString::Format( _( "Symbol '%s' is rotated by an angle of %.1f " //format:allow
2116 "degrees in the original CADSTAR design but "
2117 "KiCad only supports rotation angles multiples "
2118 "of 90 degrees. The connecting wires will need "
2119 "manual fixing." ),
2120 aCadstarSymbol.ComponentRef.Designator,
2121 compAngle.AsDegrees() ),
2123 }
2124
2125 symbol->SetOrientation( compOrientation );
2126
2127 if( m_sheetMap.find( aCadstarSymbol.LayerID ) == m_sheetMap.end() )
2128 {
2129 m_reporter->Report( wxString::Format( _( "Symbol '%s' references sheet ID '%s' which does "
2130 "not exist in the design. The symbol was not "
2131 "loaded." ),
2132 aCadstarSymbol.ComponentRef.Designator,
2133 aCadstarSymbol.LayerID ),
2135
2136 delete symbol;
2137 return nullptr;
2138 }
2139
2140 wxString gate = ( aCadstarSymbol.GateID.IsEmpty() ) ? wxString( wxT( "A" ) ) : aCadstarSymbol.GateID;
2141 wxString partGateIndex = aCadstarSymbol.PartRef.RefID + gate;
2142
2143 //Handle pin swaps
2144 if( m_pinNumsMap.find( partGateIndex ) != m_pinNumsMap.end() )
2145 {
2146 TERMINAL_TO_PINNUM_MAP termNumMap = m_pinNumsMap.at( partGateIndex );
2147
2148 std::map<wxString, std::vector<SCH_PIN*>> pinNumToLibPinsMap;
2149
2150 for( auto& term : termNumMap )
2151 {
2152 wxString pinNum = term.second;
2153 std::vector<SCH_PIN*> pins =
2154 symbol->GetLibSymbolRef()->GetPinsByNumber( term.second );
2155 pinNumToLibPinsMap.insert( { pinNum, pins } );
2156 }
2157
2158 auto replacePinNumber =
2159 [&]( wxString aOldPinNum, wxString aNewPinNum )
2160 {
2161 if( aOldPinNum == aNewPinNum )
2162 return;
2163
2164 for( SCH_PIN* libpin : pinNumToLibPinsMap.at( aOldPinNum ) )
2165 libpin->SetNumber( HandleTextOverbar( aNewPinNum ) );
2166 };
2167
2168 //Older versions of Cadstar used pin numbers
2169 for( auto& pinPair : aCadstarSymbol.PinNumbers )
2170 {
2171 SYMBOL::PIN_NUM pin = pinPair.second;
2172
2173 replacePinNumber( termNumMap.at( pin.TerminalID ),
2174 wxString::Format( "%ld", pin.PinNum ) );
2175 }
2176
2177 //Newer versions of Cadstar use pin names
2178 for( auto& pinPair : aCadstarSymbol.PinNames )
2179 {
2180 SYMPINNAME_LABEL pin = pinPair.second;
2181 replacePinNumber( termNumMap.at( pin.TerminalID ), pin.NameOrLabel );
2182 }
2183
2184 symbol->UpdatePins();
2185 }
2186
2187 kiSheet->GetScreen()->Append( symbol );
2188
2189 return symbol;
2190}
2191
2192
2194 const EDA_ANGLE& aComponentOrientation,
2195 bool aIsMirrored,
2196 SCH_FIELD* aKiCadField )
2197{
2198 aKiCadField->SetPosition( getKiCadPoint( aCadstarAttrLoc.Position ) );
2199 aKiCadField->SetVisible( true );
2200
2201 ALIGNMENT alignment = aCadstarAttrLoc.Alignment;
2202 EDA_ANGLE textAngle = getAngle( aCadstarAttrLoc.OrientAngle );
2203
2204 if( aIsMirrored )
2205 {
2206 // We need to change the aligment when the symbol is mirrored based on the text orientation
2207 // To ensure the anchor point is the same in KiCad.
2208
2209 int textIsVertical = KiROUND( textAngle.AsDegrees() / 90.0 ) % 2;
2210
2211 if( textIsVertical )
2212 alignment = rotate180( alignment );
2213
2214 alignment = mirrorX( alignment );
2215 }
2216
2217 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, alignment,
2218 aCadstarAttrLoc.Justification,
2219 getCadstarAngle( textAngle - aComponentOrientation ),
2220 aCadstarAttrLoc.Mirror );
2221}
2222
2223
2225 EDA_ANGLE& aReturnedOrientation )
2226{
2227 int compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2228
2229 EDA_ANGLE oDeg = aOrientAngle;
2230 oDeg.Normalize180();
2231
2232 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2233 {
2234 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2235 aReturnedOrientation = ANGLE_0;
2236 }
2237 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2238 {
2239 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_90;
2240 aReturnedOrientation = ANGLE_90;
2241 }
2242 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2243 {
2244 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_180;
2245 aReturnedOrientation = ANGLE_180;
2246 }
2247 else
2248 {
2249 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_270;
2250 aReturnedOrientation = ANGLE_270;
2251 }
2252
2253 return compOrientation;
2254}
2255
2256
2259 const NETELEMENT_ID& aNetElementID )
2260{
2261 // clang-format off
2262 auto logUnknownNetElementError =
2263 [&]()
2264 {
2265 m_reporter->Report( wxString::Format( _( "Net %s references unknown net element %s. "
2266 "The net was not properly loaded and may "
2267 "require manual fixing." ),
2268 getNetName( aNet ),
2269 aNetElementID ),
2271
2272 return POINT();
2273 };
2274 // clang-format on
2275
2276 if( aNetElementID.Contains( "J" ) ) // Junction
2277 {
2278 if( aNet.Junctions.find( aNetElementID ) == aNet.Junctions.end() )
2279 return logUnknownNetElementError();
2280
2281 return aNet.Junctions.at( aNetElementID ).Location;
2282 }
2283 else if( aNetElementID.Contains( "P" ) ) // Terminal/Pin of a symbol
2284 {
2285 if( aNet.Terminals.find( aNetElementID ) == aNet.Terminals.end() )
2286 return logUnknownNetElementError();
2287
2288 SYMBOL_ID symid = aNet.Terminals.at( aNetElementID ).SymbolID;
2289 TERMINAL_ID termid = aNet.Terminals.at( aNetElementID ).TerminalID;
2290
2291 if( Schematic.Symbols.find( symid ) == Schematic.Symbols.end() )
2292 return logUnknownNetElementError();
2293
2294 SYMBOL sym = Schematic.Symbols.at( symid );
2295 SYMDEF_ID symdefid = sym.SymdefID;
2296 VECTOR2I symbolOrigin = sym.Origin;
2297
2298 if( Library.SymbolDefinitions.find( symdefid ) == Library.SymbolDefinitions.end() )
2299 return logUnknownNetElementError();
2300
2301 VECTOR2I libpinPosition =
2302 Library.SymbolDefinitions.at( symdefid ).Terminals.at( termid ).Position;
2303 VECTOR2I libOrigin = Library.SymbolDefinitions.at( symdefid ).Origin;
2304
2305 VECTOR2I pinOffset = libpinPosition - libOrigin;
2306 pinOffset.x = ( pinOffset.x * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2307 pinOffset.y = ( pinOffset.y * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2308
2309 VECTOR2I pinPosition = symbolOrigin + pinOffset;
2310 EDA_ANGLE compAngle = getAngle( sym.OrientAngle );
2311
2312 if( sym.Mirror )
2313 pinPosition.x = ( 2 * symbolOrigin.x ) - pinPosition.x;
2314
2315 EDA_ANGLE adjustedOrientation;
2316 getComponentOrientation( compAngle, adjustedOrientation );
2317
2318 RotatePoint( pinPosition, symbolOrigin, -adjustedOrientation );
2319
2320 POINT retval;
2321 retval.x = pinPosition.x;
2322 retval.y = pinPosition.y;
2323
2324 return retval;
2325 }
2326 else if( aNetElementID.Contains( "BT" ) ) // Bus Terminal
2327 {
2328 if( aNet.BusTerminals.find( aNetElementID ) == aNet.BusTerminals.end() )
2329 return logUnknownNetElementError();
2330
2331 return aNet.BusTerminals.at( aNetElementID ).SecondPoint;
2332 }
2333 else if( aNetElementID.Contains( "BLKT" ) ) // Block Terminal (sheet hierarchy connection)
2334 {
2335 if( aNet.BlockTerminals.find( aNetElementID ) == aNet.BlockTerminals.end() )
2336 return logUnknownNetElementError();
2337
2338 BLOCK_ID blockid = aNet.BlockTerminals.at( aNetElementID ).BlockID;
2339 TERMINAL_ID termid = aNet.BlockTerminals.at( aNetElementID ).TerminalID;
2340
2341 if( Schematic.Blocks.find( blockid ) == Schematic.Blocks.end() )
2342 return logUnknownNetElementError();
2343
2344 return Schematic.Blocks.at( blockid ).Terminals.at( termid ).Position;
2345 }
2346 else if( aNetElementID.Contains( "D" ) ) // Dangler
2347 {
2348 if( aNet.Danglers.find( aNetElementID ) == aNet.Danglers.end() )
2349 return logUnknownNetElementError();
2350
2351 return aNet.Danglers.at( aNetElementID ).Position;
2352 }
2353 else
2354 {
2355 return logUnknownNetElementError();
2356 }
2357}
2358
2359
2361{
2362 wxString netname = aNet.Name;
2363
2364 if( netname.IsEmpty() )
2365 netname = wxString::Format( "$%ld", aNet.SignalNum );
2366
2367 return netname;
2368}
2369
2370
2371void CADSTAR_SCH_ARCHIVE_LOADER::loadShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
2372 LINECODE_ID aCadstarLineCodeID,
2373 LAYER_ID aCadstarSheetID,
2374 SCH_LAYER_ID aKiCadSchLayerID,
2375 const VECTOR2I& aMoveVector,
2376 const EDA_ANGLE& aRotation,
2377 const double& aScalingFactor,
2378 const VECTOR2I& aTransformCentre,
2379 const bool& aMirrorInvert )
2380{
2381 int lineWidth = KiROUND( getLineThickness( aCadstarLineCodeID ) * aScalingFactor );
2382 LINE_STYLE lineStyle = getLineStyle( aCadstarLineCodeID );
2383
2384 const VERTEX* prev = &aCadstarVertices.at( 0 );
2385 const VERTEX* cur;
2386
2387 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT,
2388 "First vertex should always be a point vertex" );
2389
2390 auto pointTransform =
2391 [&]( const VECTOR2I& aV )
2392 {
2393 return applyTransform( getKiCadPoint( aV ), aMoveVector, aRotation,
2394 aScalingFactor, aTransformCentre, aMirrorInvert );
2395 };
2396
2397 for( size_t ii = 1; ii < aCadstarVertices.size(); ii++ )
2398 {
2399 cur = &aCadstarVertices.at( ii );
2400
2401 VECTOR2I transformedStartPoint = pointTransform( prev->End );
2402 VECTOR2I transformedEndPoint = pointTransform( cur->End );
2403
2404 switch( cur->Type )
2405 {
2410 {
2411 SHAPE_ARC tempArc = cur->BuildArc( transformedStartPoint, pointTransform );
2412
2413 SCH_SHAPE* arcShape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_NOTES, lineWidth );
2414 arcShape->SetArcGeometry( tempArc.GetP0(), tempArc.GetArcMid(), tempArc.GetP1() );
2415
2416 loadItemOntoKiCadSheet( aCadstarSheetID, arcShape );
2417 break;
2418 }
2419
2421 {
2422 SCH_LINE* segment = new SCH_LINE();
2423
2424 segment->SetLayer( aKiCadSchLayerID );
2425 segment->SetLineWidth( lineWidth );
2426 segment->SetLineStyle( lineStyle );
2427
2428 segment->SetStartPoint( transformedStartPoint );
2429 segment->SetEndPoint( transformedEndPoint );
2430
2431 loadItemOntoKiCadSheet( aCadstarSheetID, segment );
2432 break;
2433 }
2434
2435 default:
2436 wxFAIL_MSG( "Unknown CADSTAR Vertex type" );
2437 }
2438
2439 prev = cur;
2440 }
2441}
2442
2443
2445 const LAYER_ID& aCadstarSheetIDOverride,
2446 SCH_LAYER_ID aKiCadSchLayerID,
2447 const VECTOR2I& aMoveVector,
2448 const EDA_ANGLE& aRotation,
2449 const double& aScalingFactor,
2450 const VECTOR2I& aTransformCentre,
2451 const bool& aMirrorInvert )
2452{
2453 loadShapeVertices( aCadstarFigure.Shape.Vertices, aCadstarFigure.LineCodeID,
2454 aCadstarSheetIDOverride, aKiCadSchLayerID, aMoveVector, aRotation,
2455 aScalingFactor, aTransformCentre, aMirrorInvert );
2456
2457 for( const CUTOUT& cutout : aCadstarFigure.Shape.Cutouts )
2458 {
2459 loadShapeVertices( cutout.Vertices, aCadstarFigure.LineCodeID, aCadstarSheetIDOverride,
2460 aKiCadSchLayerID, aMoveVector, aRotation, aScalingFactor,
2461 aTransformCentre, aMirrorInvert );
2462 }
2463}
2464
2465
2467 const VECTOR2I& aPosition,
2468 const VECTOR2I& aSheetSize,
2469 const SCH_SHEET_PATH& aParentSheet )
2470{
2471 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) == m_sheetMap.end(), ,
2472 "Sheet already loaded!" );
2473
2474 SCH_SHEET* sheet = new SCH_SHEET(
2475 /* aParent */ aParentSheet.Last(),
2476 /* aPosition */ aPosition,
2477 /* aSize */ VECTOR2I( aSheetSize ) );
2478 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
2479 SCH_SHEET_PATH instance( aParentSheet );
2480
2481 sheet->SetScreen( screen );
2482
2483 wxString name = Sheets.SheetNames.at( aCadstarSheetID );
2484
2486
2487 int sheetNum = getSheetNumber( aCadstarSheetID );
2488 wxString loadedFilename = wxFileName( Filename ).GetName();
2489 std::string filename = wxString::Format( "%s_%02d", loadedFilename, sheetNum ).ToStdString();
2490
2491 ReplaceIllegalFileNameChars( filename );
2492 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
2493
2494 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( filename );
2495
2496 wxFileName fn( m_schematic->Project().GetProjectPath() + filename );
2497 sheet->GetScreen()->SetFileName( fn.GetFullPath() );
2498 aParentSheet.Last()->GetScreen()->Append( sheet );
2499 instance.push_back( sheet );
2500
2501 wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
2502 instance.SetPageNumber( pageNumStr );
2503
2504 sheet->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
2505
2506 m_sheetMap.insert( { aCadstarSheetID, sheet } );
2507
2508 loadChildSheets( aCadstarSheetID, instance );
2509}
2510
2511
2513 const SCH_SHEET_PATH& aSheet )
2514{
2515 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end(), ,
2516 "FIXME! Parent sheet should be loaded before attempting to load subsheets" );
2517
2518 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2519 {
2520 BLOCK& block = blockPair.second;
2521
2522 if( block.LayerID == aCadstarSheetID && block.Type == BLOCK::TYPE::CHILD )
2523 {
2524 if( block.AssocLayerID == wxT( "NO_LINK" ) )
2525 {
2526 if( block.Figures.size() > 0 )
2527 {
2528 m_reporter->Report( wxString::Format( _( "The block ID %s (Block name: '%s') "
2529 "is drawn on sheet '%s' but is not "
2530 "linked to another sheet in the "
2531 "design. KiCad requires all sheet "
2532 "symbols to be associated to a sheet, "
2533 "so the block was not loaded." ),
2534 block.ID, block.Name,
2535 Sheets.SheetNames.at( aCadstarSheetID ) ),
2537 }
2538
2539 continue;
2540 }
2541
2542 // In KiCad you can only draw rectangular shapes whereas in Cadstar arbitrary shapes
2543 // are allowed. We will calculate the extents of the Cadstar shape and draw a rectangle
2544
2545 std::pair<VECTOR2I, VECTOR2I> blockExtents;
2546
2547 if( block.Figures.size() > 0 )
2548 {
2549 blockExtents = getFigureExtentsKiCad( block.Figures.begin()->second );
2550 }
2551 else
2552 {
2553 THROW_IO_ERROR( wxString::Format( _( "The CADSTAR schematic might be corrupt: "
2554 "Block %s references a child sheet but has no "
2555 "Figure defined." ),
2556 block.ID ) );
2557 }
2558
2559 loadSheetAndChildSheets( block.AssocLayerID, blockExtents.first, blockExtents.second,
2560 aSheet );
2561
2562 // Hide all KiCad sheet properties (sheet name/filename is not applicable in CADSTAR)
2563 SCH_SHEET* loadedSheet = m_sheetMap.at( block.AssocLayerID );
2564 std::vector<SCH_FIELD> fields = loadedSheet->GetFields();
2565
2566 for( SCH_FIELD& field : fields )
2567 {
2568 field.SetVisible( false );
2569 }
2570
2571 if( block.HasBlockLabel )
2572 {
2573 //@todo use below code when KiCad supports multi-line fields
2574 /*
2575 // Add the block label as a separate field
2576 SCH_FIELD blockNameField( getKiCadPoint( block.BlockLabel.Position ), 2,
2577 loadedSheet, wxString( "Block name" ) );
2578 blockNameField.SetText( block.Name );
2579 blockNameField.SetVisible( true );
2580
2581 applyTextSettings( &blockNameField,
2582 block.BlockLabel.TextCodeID,
2583 block.BlockLabel.Alignment,
2584 block.BlockLabel.Justification,
2585 block.BlockLabel.OrientAngle,
2586 block.BlockLabel.Mirror );
2587
2588 fields.push_back( blockNameField );*/
2589
2590 // For now as as a text item (supports multi-line properly)
2591 SCH_TEXT* kiTxt = new SCH_TEXT();
2592
2593 kiTxt->SetParent( m_schematic );
2594 kiTxt->SetPosition( getKiCadPoint( block.BlockLabel.Position ) );
2595 kiTxt->SetText( block.Name );
2596
2599 block.BlockLabel.Mirror );
2600
2601 loadItemOntoKiCadSheet( aCadstarSheetID, kiTxt );
2602 }
2603
2604 loadedSheet->SetFields( fields );
2605 }
2606 }
2607}
2608
2609
2610std::vector<CADSTAR_SCH_ARCHIVE_LOADER::LAYER_ID> CADSTAR_SCH_ARCHIVE_LOADER::findOrphanSheets()
2611{
2612 std::vector<LAYER_ID> childSheets, orphanSheets;
2613
2614 //Find all sheets that are child of another
2615 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2616 {
2617 BLOCK& block = blockPair.second;
2618 LAYER_ID& assocSheetID = block.AssocLayerID;
2619
2620 if( block.Type == BLOCK::TYPE::CHILD )
2621 childSheets.push_back( assocSheetID );
2622 }
2623
2624 //Add sheets that do not have a parent
2625 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2626 {
2627 if( std::find( childSheets.begin(), childSheets.end(), sheetID ) == childSheets.end() )
2628 orphanSheets.push_back( sheetID );
2629 }
2630
2631 return orphanSheets;
2632}
2633
2634
2636{
2637 int i = 1;
2638
2639 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2640 {
2641 if( sheetID == aCadstarSheetID )
2642 return i;
2643
2644 ++i;
2645 }
2646
2647 return -1;
2648}
2649
2650
2652 SCH_ITEM* aItem )
2653{
2654 wxCHECK_MSG( aItem, /*void*/, wxT( "aItem is null" ) );
2655
2656 if( aCadstarSheetID == "ALL_SHEETS" )
2657 {
2658 SCH_ITEM* duplicateItem = nullptr;
2659
2660 for( std::pair<LAYER_ID, SHEET_NAME> sheetPair : Sheets.SheetNames )
2661 {
2662 LAYER_ID sheetID = sheetPair.first;
2663 duplicateItem = aItem->Duplicate( IGNORE_PARENT_GROUP );
2664 m_sheetMap.at( sheetID )->GetScreen()->Append( aItem->Duplicate( IGNORE_PARENT_GROUP ) );
2665 }
2666
2667 //Get rid of the extra copy:
2668 delete aItem;
2669 aItem = duplicateItem;
2670 }
2671 else if( aCadstarSheetID == "NO_SHEET" )
2672 {
2673 wxFAIL_MSG( wxT( "Trying to add an item to NO_SHEET? This might be a documentation symbol." ) );
2674 }
2675 else
2676 {
2677 if( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end() )
2678 {
2679 m_sheetMap.at( aCadstarSheetID )->GetScreen()->Append( aItem );
2680 }
2681 else
2682 {
2683 delete aItem;
2684 wxFAIL_MSG( wxT( "Unknown Sheet ID." ) );
2685 }
2686 }
2687}
2688
2689
2692 const wxString& aSymDefAlternate )
2693{
2694 if( m_SymDefNamesCache.size() != Library.SymbolDefinitions.size() )
2695 {
2696 // Re-initialise
2697 m_SymDefNamesCache.clear();
2699
2700 // Create a lower case cache to avoid searching each time
2701 for( auto& [id, symdef] : Library.SymbolDefinitions )
2702 {
2703 wxString refKey = symdef.ReferenceName.Lower();
2704 wxString altKey = symdef.Alternate.Lower();
2705
2706 m_SymDefNamesCache[{ refKey, altKey }] = id;
2707
2708 // Secondary cache to find symbols just by the Name (e.g. if the alternate
2709 // does not exist, we still want to return a symbo - the same behaviour
2710 // as CADSTAR
2711
2712 if( !m_DefaultSymDefNamesCache.count( refKey ) )
2713 {
2714 m_DefaultSymDefNamesCache.insert( { refKey, id } );
2715 }
2716 else if( altKey.IsEmpty() )
2717 {
2718 // Always use the empty alternate if it exists
2719 m_DefaultSymDefNamesCache[refKey] = id;
2720 }
2721 }
2722 }
2723
2724 wxString refKeyToFind = aSymdefName.Lower();
2725 wxString altKeyToFind = aSymDefAlternate.Lower();
2726
2727 if( m_SymDefNamesCache.count( { refKeyToFind, altKeyToFind } ) )
2728 {
2729 return m_SymDefNamesCache[{ refKeyToFind, altKeyToFind }];
2730 }
2731 else if( m_DefaultSymDefNamesCache.count( refKeyToFind ) )
2732 {
2733 return m_DefaultSymDefNamesCache[refKeyToFind];
2734 }
2735
2736 return SYMDEF_ID();
2737}
2738
2739
2741{
2742 // Use CADSTAR visibility settings to determine if an attribute is visible
2743 if( AttrColors.AttributeColors.find( aCadstarAttributeID ) != AttrColors.AttributeColors.end() )
2744 return AttrColors.AttributeColors.at( aCadstarAttributeID ).IsVisible;
2745
2746 return false; // If there is no visibility setting, assume not displayed
2747}
2748
2749
2751{
2752 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2753 != Assignments.Codedefs.LineCodes.end(),
2754 schIUScale.MilsToIU( DEFAULT_WIRE_WIDTH_MILS ) );
2755
2756 return getKiCadLength( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Width );
2757}
2758
2759
2761{
2762 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2763 != Assignments.Codedefs.LineCodes.end(),
2765
2766 // clang-format off
2767 switch( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Style )
2768 {
2769 case LINESTYLE::DASH: return LINE_STYLE::DASH;
2771 case LINESTYLE::DASHDOTDOT: return LINE_STYLE::DASHDOT; //TODO: update in future
2772 case LINESTYLE::DOT: return LINE_STYLE::DOT;
2774 default: return LINE_STYLE::DEFAULT;
2775 }
2776 // clang-format on
2777}
2778
2779
2782{
2783 wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID )
2784 != Assignments.Codedefs.TextCodes.end(),
2785 TEXTCODE() );
2786
2787 return Assignments.Codedefs.TextCodes.at( aCadstarTextCodeID );
2788}
2789
2790
2792{
2793 TEXTCODE txtCode = getTextCode( aCadstarTextCodeID );
2794
2795 return KiROUND( (double) getKiCadLength( txtCode.Height ) * TXT_HEIGHT_RATIO );
2796}
2797
2798
2800{
2801 wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
2802 != Assignments.Codedefs.AttributeNames.end(),
2803 aCadstarAttributeID );
2804
2805 return Assignments.Codedefs.AttributeNames.at( aCadstarAttributeID ).Name;
2806}
2807
2808
2811{
2812 wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
2813
2814 return Parts.PartDefinitions.at( aCadstarPartID );
2815}
2816
2817
2820{
2821 wxCHECK( Assignments.Codedefs.RouteCodes.find( aCadstarRouteCodeID )
2822 != Assignments.Codedefs.RouteCodes.end(),
2823 ROUTECODE() );
2824
2825 return Assignments.Codedefs.RouteCodes.at( aCadstarRouteCodeID );
2826}
2827
2828
2829CADSTAR_SCH_ARCHIVE_LOADER::PART::DEFINITION::PIN
2831 const TERMINAL_ID& aTerminalID )
2832{
2833 for( std::pair<PART_DEFINITION_PIN_ID, PART::DEFINITION::PIN> pinPair :
2834 aCadstarPart.Definition.Pins )
2835 {
2836 PART::DEFINITION::PIN partPin = pinPair.second;
2837
2838 if( partPin.TerminalGate == aGateID && partPin.TerminalPin == aTerminalID )
2839 return partPin;
2840 }
2841
2842 return PART::DEFINITION::PIN();
2843}
2844
2845
2864
2866{
2867 if( aCadstarGateID.IsEmpty() )
2868 return 1;
2869
2870 return (int) aCadstarGateID.Upper().GetChar( 0 ) - (int) wxUniChar( 'A' ) + 1;
2871}
2872
2873
2874SPIN_STYLE CADSTAR_SCH_ARCHIVE_LOADER::getSpinStyle( const long long& aCadstarOrientation,
2875 bool aMirror )
2876{
2877 EDA_ANGLE orientation = getAngle( aCadstarOrientation );
2878 SPIN_STYLE spinStyle = getSpinStyle( orientation );
2879
2880 if( aMirror )
2881 {
2882 spinStyle = spinStyle.RotateCCW();
2883 spinStyle = spinStyle.RotateCCW();
2884 }
2885
2886 return spinStyle;
2887}
2888
2889
2891{
2892 SPIN_STYLE spinStyle = SPIN_STYLE::LEFT;
2893
2894 EDA_ANGLE oDeg = aOrientation;
2895 oDeg.Normalize180();
2896
2897 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2898 spinStyle = SPIN_STYLE::RIGHT; // 0deg
2899 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2900 spinStyle = SPIN_STYLE::UP; // 90deg
2901 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2902 spinStyle = SPIN_STYLE::LEFT; // 180deg
2903 else
2904 spinStyle = SPIN_STYLE::BOTTOM; // 270deg
2905
2906 return spinStyle;
2907}
2908
2909
2912{
2913 switch( aCadstarAlignment )
2914 {
2915 // Change left to right:
2920
2921 //Change right to left:
2925
2926 // Center alignment does not mirror:
2929 case ALIGNMENT::TOPCENTER: return aCadstarAlignment;
2930
2931 // Shouldn't be here
2932 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2933 }
2934}
2935
2936
2939{
2940 switch( aCadstarAlignment )
2941 {
2952
2953 // Shouldn't be here
2954 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2955 }
2956}
2957
2958
2960 const TEXTCODE_ID& aCadstarTextCodeID )
2961{
2962 // Ensure we have no Cadstar overbar characters
2963 wxString escapedText = HandleTextOverbar( aKiCadTextItem->GetText() );
2964 aKiCadTextItem->SetText( escapedText );
2965
2966 if( !Assignments.Codedefs.TextCodes.count( aCadstarTextCodeID ) )
2967 return;
2968
2969 TEXTCODE textCode = getTextCode( aCadstarTextCodeID );
2970 int textHeight = KiROUND( (double) getKiCadLength( textCode.Height ) * TXT_HEIGHT_RATIO );
2971 int textWidth = getKiCadLength( textCode.Width );
2972
2973 // The width is zero for all non-cadstar fonts. Using a width equal to 2/3 the height seems
2974 // to work well for most fonts.
2975 if( textWidth == 0 )
2976 textWidth = getKiCadLength( 2LL * textCode.Height / 3LL );
2977
2978 aKiCadTextItem->SetTextWidth( textWidth );
2979 aKiCadTextItem->SetTextHeight( textHeight );
2980
2981#if 0
2982 // EEschema currently supports only normal vs bold for text thickness.
2983 aKiCadTextItem->SetTextThickness( getKiCadLength( textCode.LineWidth ) );
2984#endif
2985
2986 // Must come after SetTextSize()
2987 aKiCadTextItem->SetBold( textCode.Font.Modifier1 == FONT_BOLD );
2988 aKiCadTextItem->SetItalic( textCode.Font.Italic );
2989}
2990
2991
2993 const TEXTCODE_ID& aCadstarTextCodeID,
2994 const ALIGNMENT& aCadstarAlignment,
2995 const JUSTIFICATION& aCadstarJustification,
2996 const long long aCadstarOrientAngle,
2997 bool aMirrored )
2998{
2999 applyTextCodeIfExists( aKiCadTextItem, aCadstarTextCodeID );
3000 aKiCadTextItem->SetTextAngle( getAngle( aCadstarOrientAngle ) );
3001
3002 // Justification ignored for now as not supported in Eeschema, but leaving this code in
3003 // place for future upgrades.
3004 // TODO update this when Eeschema supports justification independent of anchor position.
3005 ALIGNMENT textAlignment = aCadstarAlignment;
3006
3007 // KiCad mirrors the justification and alignment when the symbol is mirrored but CADSTAR
3008 // specifies it post-mirroring. In contrast, if the text item itself is mirrored (not
3009 // supported in KiCad), CADSTAR specifies the alignment and justification pre-mirroring
3010 if( aMirrored )
3011 textAlignment = mirrorX( aCadstarAlignment );
3012
3013 auto setAlignment =
3014 [&]( EDA_TEXT* aText, ALIGNMENT aAlignment )
3015 {
3016 switch( aAlignment )
3017 {
3018 case ALIGNMENT::NO_ALIGNMENT: // Bottom left of the first line
3019 //No exact KiCad equivalent, so lets move the position of the text
3025 break;
3026
3030 break;
3031
3035 break;
3036
3040 break;
3041
3045 break;
3046
3050 break;
3051
3052 case ALIGNMENT::TOPLEFT:
3055 break;
3056
3060 break;
3061
3065 break;
3066 }
3067 };
3068
3069 SPIN_STYLE spin = getSpinStyle( aCadstarOrientAngle, aMirrored );
3070 EDA_ITEM* textEdaItem = dynamic_cast<EDA_ITEM*>( aKiCadTextItem );
3071 wxCHECK( textEdaItem, /* void */ ); // ensure this is a EDA_ITEM
3072
3073 if( textEdaItem->Type() == SCH_FIELD_T )
3074 {
3075 // Spin style not used. All text justifications are permitted. However, only orientations
3076 // of 0 deg or 90 deg are supported
3077 EDA_ANGLE angle = aKiCadTextItem->GetTextAngle();
3078 angle.Normalize();
3079
3080 int quadrant = KiROUND( angle.AsDegrees() / 90.0 );
3081 quadrant %= 4;
3082
3083 switch( quadrant )
3084 {
3085 case 0:
3086 angle = ANGLE_HORIZONTAL;
3087 break;
3088 case 1:
3089 angle = ANGLE_VERTICAL;
3090 break;
3091 case 2:
3092 angle = ANGLE_HORIZONTAL;
3093 textAlignment = rotate180( textAlignment );
3094 break;
3095 case 3:
3096 angle = ANGLE_VERTICAL;
3097 textAlignment = rotate180( textAlignment );
3098 break;
3099 default:
3100 wxFAIL_MSG( "Unknown Quadrant" );
3101 }
3102
3103 aKiCadTextItem->SetTextAngle( angle );
3104 setAlignment( aKiCadTextItem, textAlignment );
3105 }
3106 else if( textEdaItem->Type() == SCH_TEXT_T )
3107 {
3108 // Note spin style in a SCH_TEXT results in a vertical alignment GR_TEXT_V_ALIGN_BOTTOM
3109 // so need to adjust the location of the text element based on Cadstar's original text
3110 // alignment (anchor position).
3111 setAlignment( aKiCadTextItem, textAlignment );
3112 BOX2I bb = textEdaItem->GetBoundingBox();
3113 int off = static_cast<SCH_TEXT*>( aKiCadTextItem )->GetTextOffset();
3114 VECTOR2I pos;
3115
3116 // Change the anchor point of the text item to make it match the same bounding box
3117 // And correct the error introduced by the text offsetting in KiCad
3118 switch( spin )
3119 {
3120 case SPIN_STYLE::BOTTOM: pos = { bb.GetRight() - off, bb.GetTop() }; break;
3121 case SPIN_STYLE::UP: pos = { bb.GetRight() - off, bb.GetBottom() }; break;
3122 case SPIN_STYLE::LEFT: pos = { bb.GetRight() , bb.GetBottom() + off }; break;
3123 case SPIN_STYLE::RIGHT: pos = { bb.GetLeft() , bb.GetBottom() + off }; break;
3124 default: wxFAIL_MSG( "Unexpected Spin Style" ); break;
3125 }
3126
3127 aKiCadTextItem->SetTextPos( pos );
3128
3129 switch( spin )
3130 {
3131 case SPIN_STYLE::RIGHT: // Horiz Normal Orientation
3132 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3133 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3134 break;
3135
3136 case SPIN_STYLE::UP: // Vert Orientation UP
3137 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3138 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3139 break;
3140
3141 case SPIN_STYLE::LEFT: // Horiz Orientation - Right justified
3142 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3143 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3144 break;
3145
3146 case SPIN_STYLE::BOTTOM: // Vert Orientation BOTTOM
3147 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3148 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3149 break;
3150
3151 default:
3152 wxFAIL_MSG( "Unexpected Spin Style" );
3153 break;
3154 }
3155
3156 aKiCadTextItem->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
3157 }
3158 else if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( aKiCadTextItem ) )
3159 {
3160 // We don't want to change position of net labels as that would break connectivity
3161 label->SetSpinStyle( spin );
3162 }
3163 else
3164 {
3165 wxFAIL_MSG( "Unexpected item type" );
3166 }
3167}
3168
3169
3171{
3172 SCH_TEXT* kiTxt = new SCH_TEXT();
3173
3174 kiTxt->SetParent( m_schematic ); // set to the schematic for now to avoid asserts
3175 kiTxt->SetPosition( getKiCadPoint( aCadstarTextElement.Position ) );
3176 kiTxt->SetText( aCadstarTextElement.Text );
3177
3178 applyTextSettings( kiTxt, aCadstarTextElement.TextCodeID, aCadstarTextElement.Alignment,
3179 aCadstarTextElement.Justification, aCadstarTextElement.OrientAngle,
3180 aCadstarTextElement.Mirror );
3181
3182 return kiTxt;
3183}
3184
3185
3187 long long aScalingFactorNumerator,
3188 long long aScalingFactorDenominator )
3189{
3190 LIB_SYMBOL* retval = new LIB_SYMBOL( *aSymbol );
3191
3192 if( aScalingFactorNumerator == aScalingFactorDenominator )
3193 return retval; // 1:1 scale, nothing to do
3194
3195 auto scaleLen =
3196 [&]( int aLength ) -> int
3197 {
3198 return( aLength * aScalingFactorNumerator ) / aScalingFactorDenominator;
3199 };
3200
3201 auto scalePt =
3202 [&]( VECTOR2I aCoord ) -> VECTOR2I
3203 {
3204 return VECTOR2I( scaleLen( aCoord.x ), scaleLen( aCoord.y ) );
3205 };
3206
3207 auto scaleSize =
3208 [&]( VECTOR2I aSize ) -> VECTOR2I
3209 {
3210 return VECTOR2I( scaleLen( aSize.x ), scaleLen( aSize.y ) );
3211 };
3212
3213 LIB_ITEMS_CONTAINER& items = retval->GetDrawItems();
3214
3215 for( SCH_ITEM& item : items )
3216 {
3217 switch( item.Type() )
3218 {
3220 {
3221 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
3222
3223 if( shape.GetShape() == SHAPE_T::ARC )
3224 {
3225 shape.SetPosition( scalePt( shape.GetPosition() ) );
3226 shape.SetStart( scalePt( shape.GetStart() ) );
3227 shape.SetEnd( scalePt( shape.GetEnd() ) );
3228 }
3229 else if( shape.GetShape() == SHAPE_T::POLY )
3230 {
3231 SHAPE_LINE_CHAIN& poly = shape.GetPolyShape().Outline( 0 );
3232
3233 for( size_t ii = 0; ii < poly.GetPointCount(); ++ii )
3234 poly.SetPoint( ii, scalePt( poly.CPoint( ii ) ) );
3235 }
3236 break;
3237 }
3238
3239 case KICAD_T::SCH_PIN_T:
3240 {
3241 SCH_PIN& pin = static_cast<SCH_PIN&>( item );
3242
3243 pin.SetPosition( scalePt( pin.GetPosition() ) );
3244 pin.SetLength( scaleLen( pin.GetLength() ) );
3245 break;
3246 }
3247
3249 {
3250 SCH_TEXT& txt = static_cast<SCH_TEXT&>( item );
3251
3252 txt.SetPosition( scalePt( txt.GetPosition() ) );
3253 txt.SetTextSize( scaleSize( txt.GetTextSize() ) );
3254 break;
3255 }
3256
3257 default:
3258 break;
3259 }
3260 }
3261
3262 return retval;
3263}
3264
3265
3266void CADSTAR_SCH_ARCHIVE_LOADER::fixUpLibraryPins( LIB_SYMBOL* aSymbolToFix, int aGateNumber )
3267{
3268 auto compLambda =
3269 []( const VECTOR2I& aA, const VECTOR2I& aB )
3270 {
3271 return LexicographicalCompare( aA, aB ) < 0;
3272 };
3273
3274 // Store a list of vertical or horizontal segments in the symbol
3275 // Note: Need the custom comparison function to ensure the map is sorted correctly
3276 std::map<VECTOR2I, SHAPE_LINE_CHAIN, decltype( compLambda )> uniqueSegments( compLambda );
3277
3278 LIB_ITEMS_CONTAINER::ITERATOR shapeIt = aSymbolToFix->GetDrawItems().begin( SCH_SHAPE_T );
3279
3280 for( ; shapeIt != aSymbolToFix->GetDrawItems().end( SCH_SHAPE_T ); ++shapeIt )
3281 {
3282 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( *shapeIt );
3283
3284 if( aGateNumber > 0 && shape.GetUnit() != aGateNumber )
3285 continue;
3286
3287 if( shape.GetShape() != SHAPE_T::POLY )
3288 continue;
3289
3290 SHAPE_LINE_CHAIN poly = shape.GetPolyShape().Outline( 0 );
3291
3292 if( poly.GetPointCount() == 2 )
3293 {
3294 VECTOR2I pt0 = poly.CPoint( 0 );
3295 VECTOR2I pt1 = poly.CPoint( 1 );
3296
3297 if( pt0 != pt1 && uniqueSegments.count( pt0 ) == 0 && uniqueSegments.count( pt1 ) == 0 )
3298 {
3299 // we are only interested in vertical or horizontal segments
3300 if( pt0.x == pt1.x || pt0.y == pt1.y )
3301 {
3302 uniqueSegments.insert( { pt0, poly } );
3303 uniqueSegments.insert( { pt1, poly } );
3304 }
3305 }
3306 }
3307 }
3308
3309 for( SCH_PIN* pin : aSymbolToFix->GetGraphicalPins( aGateNumber, 0 ) )
3310 {
3311 auto setPinOrientation =
3312 [&]( const EDA_ANGLE& aAngle )
3313 {
3314 EDA_ANGLE angle( aAngle );
3315 angle.Normalize180();
3316
3317 if( angle >= -ANGLE_45 && angle <= ANGLE_45 )
3318 pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); // 0 degrees
3319 else if( angle >= ANGLE_45 && angle <= ANGLE_135 )
3320 pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); // 90 degrees
3321 else if( angle >= ANGLE_135 || angle <= -ANGLE_135 )
3322 pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); // 180 degrees
3323 else
3324 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); // -90 degrees
3325 };
3326
3327 if( uniqueSegments.count( pin->GetPosition() ) )
3328 {
3329 SHAPE_LINE_CHAIN& poly = uniqueSegments.at( pin->GetPosition() );
3330
3331 VECTOR2I otherPt = poly.CPoint( 0 );
3332
3333 if( otherPt == pin->GetPosition() )
3334 otherPt = poly.CPoint( 1 );
3335
3336 VECTOR2I vec( otherPt - pin->GetPosition() );
3337
3338 pin->SetLength( vec.EuclideanNorm() );
3339 setPinOrientation( EDA_ANGLE( vec ) );
3340 }
3341 }
3342}
3343
3344
3345std::pair<VECTOR2I, VECTOR2I>
3347{
3348 VECTOR2I upperLeft( Assignments.Settings.DesignLimit.x, 0 );
3349 VECTOR2I lowerRight( 0, Assignments.Settings.DesignLimit.y );
3350
3351 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3352 {
3353 if( upperLeft.x > v.End.x )
3354 upperLeft.x = v.End.x;
3355
3356 if( upperLeft.y < v.End.y )
3357 upperLeft.y = v.End.y;
3358
3359 if( lowerRight.x < v.End.x )
3360 lowerRight.x = v.End.x;
3361
3362 if( lowerRight.y > v.End.y )
3363 lowerRight.y = v.End.y;
3364 }
3365
3366 for( CUTOUT cutout : aCadstarFigure.Shape.Cutouts )
3367 {
3368 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3369 {
3370 if( upperLeft.x > v.End.x )
3371 upperLeft.x = v.End.x;
3372
3373 if( upperLeft.y < v.End.y )
3374 upperLeft.y = v.End.y;
3375
3376 if( lowerRight.x < v.End.x )
3377 lowerRight.x = v.End.x;
3378
3379 if( lowerRight.y > v.End.y )
3380 lowerRight.y = v.End.y;
3381 }
3382 }
3383
3384 VECTOR2I upperLeftKiCad = getKiCadPoint( upperLeft );
3385 VECTOR2I lowerRightKiCad = getKiCadPoint( lowerRight );
3386
3387 VECTOR2I size = lowerRightKiCad - upperLeftKiCad;
3388
3389 return { upperLeftKiCad, VECTOR2I( abs( size.x ), abs( size.y ) ) };
3390}
3391
3392
3394{
3395 VECTOR2I retval;
3396
3397 retval.x = getKiCadLength( aCadstarPoint.x - m_designCenter.x );
3398 retval.y = -getKiCadLength( aCadstarPoint.y - m_designCenter.y );
3399
3400 return retval;
3401}
3402
3403
3405 const VECTOR2I& aCadstarCentre )
3406{
3407 VECTOR2I retval;
3408
3409 retval.x = getKiCadLength( aCadstarPoint.x - aCadstarCentre.x );
3410 retval.y = -getKiCadLength( aCadstarPoint.y - aCadstarCentre.y );
3411
3412 return retval;
3413}
3414
3415
3417 const VECTOR2I& aMoveVector,
3418 const EDA_ANGLE& aRotation,
3419 const double& aScalingFactor,
3420 const VECTOR2I& aTransformCentre,
3421 const bool& aMirrorInvert )
3422{
3423 VECTOR2I retVal = aPoint;
3424
3425 if( aScalingFactor != 1.0 )
3426 {
3427 //scale point
3428 retVal -= aTransformCentre;
3429 retVal.x = KiROUND( retVal.x * aScalingFactor );
3430 retVal.y = KiROUND( retVal.y * aScalingFactor );
3431 retVal += aTransformCentre;
3432 }
3433
3434 if( aMirrorInvert )
3435 MIRROR( retVal.x, aTransformCentre.x );
3436
3437 if( !aRotation.IsZero() )
3438 RotatePoint( retVal, aTransformCentre, aRotation );
3439
3440 if( aMoveVector != VECTOR2I{ 0, 0 } )
3441 retVal += aMoveVector;
3442
3443 return retVal;
3444}
3445
3446
3448{
3449 return sqrt( ( (double) aPoint.x * (double) aPoint.x )
3450 + ( (double) aPoint.y * (double) aPoint.y ) );
3451}
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
constexpr double SCH_IU_PER_MM
Schematic internal units 1=100nm.
Definition base_units.h:70
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
CADSTAR_PIN_TYPE
file: cadstar_archive_objects.h Contains common object definitions
@ OUTPUT_NOT_OR
Output pin not OR tieable.
@ TRISTATE_DRIVER
Tristate output pin.
@ OUTPUT_OR
Output pin OR tieable.
@ UNCOMMITTED
Uncommitted pin (default)
@ TRISTATE_INPUT
Tristate input pin.
@ TRISTATE_BIDIR
Tristate bi-directional driver pin.
@ OUTPUT_NOT_NORM_OR
Output pin not normally OR tieable.
#define SYMBOL_NAME_ATTRID
Symbol Name attribute ID - used for placement of designators on the schematic.
#define SIGNALNAME_ORIGIN_ATTRID
#define LINK_ORIGIN_ATTRID
#define PART_NAME_ATTRID
const wxString PartAcceptanceFieldName
const wxString PartNumberFieldName
const wxString PartNameFieldName
const wxString PartVersionFieldName
Loads a csa file into a KiCad SCHEMATIC object.
constexpr Vec Centre() const
Definition box2.h:93
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:654
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr const SizeVec & GetSize() const
Definition box2.h:202
constexpr coord_type GetTop() const
Definition box2.h:225
constexpr coord_type GetBottom() const
Definition box2.h:218
static wxString EscapeFieldText(const wxString &aFieldText)
@ FRACTIONALGRID
Param1 = Units, Param2 = Divisor.
static const std::map< TEXT_FIELD_NAME, wxString > CADSTAR_TO_KICAD_FIELDS
Map between CADSTAR fields and KiCad text variables.
long TERMINAL_ID
Terminal is the pin identifier in the schematic.
TEXT_FIELD_NAME
These are special fields in text objects enclosed between the tokens '<@' and '>' such as <@[FIELD_NA...
ALIGNMENT
From CADSTAR Help: "Text Alignment enables you to define the position of an alignment origin for all ...
@ NO_ALIGNMENT
NO_ALIGNMENT has different meaning depending on the object type.
static wxString generateLibName(const wxString &aRefName, const wxString &aAlternateName)
wxString LAYER_ID
ID of a Sheet (if schematic) or board Layer (if PCB)
static void FixTextPositionNoAlignment(EDA_TEXT *aKiCadTextItem)
Correct the position of a text element that had NO_ALIGNMENT in CADSTAR.
@ OPENSHAPE
Unfilled open shape. Cannot have cutouts.
@ SOLID
Filled closed shape (solid fill).
@ HATCHED
Filled closed shape (hatch fill).
static const double TXT_HEIGHT_RATIO
CADSTAR fonts are drawn on a 24x24 integer matrix, where the each axis goes from 0 to 24.
void checkPoint()
Updates m_progressReporter or throws if user canceled.
static wxString HandleTextOverbar(wxString aCadstarString)
Convert a string with CADSTAR overbar characters to equivalent in KiCad.
JUSTIFICATION
From CADSTAR Help: "Multi Line Text can also be justified as Left, Centre or Right.
PROGRESS_REPORTER * m_progressReporter
bool CheckFileHeader(const std::filesystem::path &aPath) const
CADSTAR_PARTS_LIB_MODEL ReadFile(const std::filesystem::path &aPath) const
void loadItemOntoKiCadSheet(const LAYER_ID &aCadstarSheetID, SCH_ITEM *aItem)
void Load(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet)
Loads a CADSTAR Schematic Archive file into the KiCad SCHEMATIC object given.
ROUTECODE getRouteCode(const ROUTECODE_ID &aCadstarRouteCodeID)
static wxString CreateLibName(const wxFileName &aFileName, const SCH_SHEET *aRootSheet)
std::map< BLOCK_PIN_ID, SCH_HIERLABEL * > m_sheetPinMap
Cadstar->KiCad Sheet Pins.
VECTOR2I applyTransform(const VECTOR2I &aPoint, const VECTOR2I &aMoveVector={ 0, 0 }, const EDA_ANGLE &aRotation=ANGLE_0, const double &aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
std::map< SYMBOL_ID, SCH_GLOBALLABEL * > m_globalLabelsMap
Cadstar->KiCad Global Labels.
SCH_SYMBOL * loadSchematicSymbol(const SYMBOL &aCadstarSymbol, const LIB_SYMBOL &aKiCadPart, EDA_ANGLE &aComponentOrientation)
void applyTextSettings(EDA_TEXT *aKiCadTextItem, const TEXTCODE_ID &aCadstarTextCodeID, const ALIGNMENT &aCadstarAlignment, const JUSTIFICATION &aCadstarJustification, const long long aCadstarOrientAngle=0, bool aMirrored=false)
void loadSheetAndChildSheets(const LAYER_ID &aCadstarSheetID, const VECTOR2I &aPosition, const VECTOR2I &aSheetSize, const SCH_SHEET_PATH &aParentSheet)
wxString getAttributeName(const ATTRIBUTE_ID &aCadstarAttributeID)
std::vector< LIB_SYMBOL * > m_loadedSymbols
Loaded symbols so far.
static SCH_FIELD * addNewFieldToSymbol(const wxString &aFieldName, LIB_SYMBOL *aKiCadSymbol)
PART getPart(const PART_ID &aCadstarPartID)
std::vector< LAYER_ID > findOrphanSheets()
void setFootprintOnSymbol(LIB_SYMBOL *aKiCadSymbol, const wxString &aFootprintName, const wxString &aFootprintAlternate)
std::map< BUS_ID, std::shared_ptr< BUS_ALIAS > > m_busesMap
Cadstar->KiCad Buses.
SCH_TEXT * getKiCadSchText(const TEXT &aCadstarTextElement)
std::map< TERMINAL_ID, wxString > TERMINAL_TO_PINNUM_MAP
Map between a terminal ID in a symbol definition to the pin number that should be imported into KiCad...
wxString getNetName(const NET_SCH &aNet)
std::pair< BLOCK_ID, TERMINAL_ID > BLOCK_PIN_ID
std::map< SYMBOL_ID, SCH_SYMBOL * > m_powerSymMap
Cadstar->KiCad Power Symbols.
std::pair< PART_ID, GATE_ID > PART_GATE_ID
VECTOR2I getKiCadLibraryPoint(const VECTOR2I &aCadstarPoint, const VECTOR2I &aCadstarCentre)
PART::DEFINITION::PIN getPartDefinitionPin(const PART &aCadstarPart, const GATE_ID &aGateID, const TERMINAL_ID &aTerminalID)
std::map< wxString, TERMINAL_ID > PINNUM_TO_TERMINAL_MAP
std::map< SYMDEF_ID, PINNUM_TO_TERMINAL_MAP > m_symDefTerminalsMap
int getTextHeightFromTextCode(const TEXTCODE_ID &aCadstarTextCodeID)
void loadChildSheets(const LAYER_ID &aCadstarSheetID, const SCH_SHEET_PATH &aSheet)
void applyToLibraryFieldAttribute(const ATTRIBUTE_LOCATION &aCadstarAttrLoc, const VECTOR2I &aSymbolOrigin, SCH_FIELD *aKiCadField)
double getPolarRadius(const VECTOR2I &aPoint)
void applyTextCodeIfExists(EDA_TEXT *aKiCadTextItem, const TEXTCODE_ID &aCadstarTextCodeID)
int getSheetNumber(const LAYER_ID &aCadstarSheetID)
int getLineThickness(const LINECODE_ID &aCadstarLineCodeID)
TEXTCODE getTextCode(const TEXTCODE_ID &aCadstarTextCodeID)
SPIN_STYLE getSpinStyle(const long long &aCadstarOrientation, bool aMirror)
std::map< wxString, LIB_SYMBOL * > m_powerSymLibMap
NetName->KiCad Power Lib Symbol.
std::map< std::pair< wxString, wxString >, SYMDEF_ID > m_SymDefNamesCache
Cache storing symbol names and alternates to symdef IDs.
std::map< PART_ID, TERMINAL_TO_PINNUM_MAP > m_pinNumsMap
Cadstar Part->KiCad Pin number map.
std::vector< LIB_SYMBOL * > LoadPartsLib(const wxString &aFilename)
ELECTRICAL_PINTYPE getKiCadPinType(const CADSTAR_PIN_TYPE &aPinType)
wxString m_footprintLibName
Name of the footprint library to prepend all footprints with.
int getKiCadLength(long long aCadstarLength)
std::map< PART_ID, LIB_SYMBOL * > m_partMap
Cadstar->KiCad Parts.
bool isAttributeVisible(const ATTRIBUTE_ID &aCadstarAttributeID)
VECTOR2I getKiCadPoint(const VECTOR2I &aCadstarPoint)
EDA_ANGLE getAngle(const long long &aCadstarAngle)
std::map< wxString, SYMDEF_ID > m_DefaultSymDefNamesCache
Cache storing symbol names (default alternate) to symdef IDs.
void loadSymbolGateAndPartFields(const SYMDEF_ID &aSymdefID, const PART &aCadstarPart, const GATE_ID &aGateID, LIB_SYMBOL *aSymbol)
void loadFigure(const FIGURE &aCadstarFigure, const LAYER_ID &aCadstarSheetIDOverride, SCH_LAYER_ID aKiCadSchLayerID, const VECTOR2I &aMoveVector={ 0, 0 }, const EDA_ANGLE &aRotation=ANGLE_0, const double &aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
std::map< PART_GATE_ID, SYMDEF_ID > m_partSymbolsMap
Map holding the symbols loaded so far for a particular PART_ID and GATE_ID.
LIB_SYMBOL * getScaledLibPart(const LIB_SYMBOL *aSymbol, long long aScalingFactorNumerator, long long aScalingFactorDenominator)
SYMDEF_ID getSymDefFromName(const wxString &aSymdefName, const wxString &aSymDefAlternate)
std::pair< VECTOR2I, VECTOR2I > getFigureExtentsKiCad(const FIGURE &aCadstarFigure)
std::map< LAYER_ID, SCH_SHEET * > m_sheetMap
Cadstar->KiCad Sheets.
void copySymbolItems(LIB_SYMBOL *aSourceSym, LIB_SYMBOL *aDestSym, int aDestUnit, bool aOverrideFields=true)
POINT getLocationOfNetElement(const NET_SCH &aNet, const NETELEMENT_ID &aNetElementID)
void fixUpLibraryPins(LIB_SYMBOL *aSymbolToFix, int aGateNumber)
std::map< SYMDEF_ID, std::unique_ptr< const LIB_SYMBOL > > m_symDefMap
Cadstar->KiCad Lib Symbols loaded so far.
std::unique_ptr< LIB_SYMBOL > loadLibPart(const CADSTAR_PART_ENTRY &aPart)
ALIGNMENT rotate180(const ALIGNMENT &aCadstarAlignment)
long long getCadstarAngle(const EDA_ANGLE &aAngle)
void loadLibrarySymbolShapeVertices(const std::vector< VERTEX > &aCadstarVertices, const VECTOR2I &aSymbolOrigin, LIB_SYMBOL *aSymbol, int aGateNumber, int aLineThickness)
LINE_STYLE getLineStyle(const LINECODE_ID &aCadstarLineCodeID)
VECTOR2I m_designCenter
Required for calculating the offset to apply to the Cadstar design so that it fits in the KiCad canva...
ALIGNMENT mirrorX(const ALIGNMENT &aCadstarAlignment)
int getComponentOrientation(const EDA_ANGLE &aOrientAngle, EDA_ANGLE &aReturnedOrientation)
void loadShapeVertices(const std::vector< VERTEX > &aCadstarVertices, LINECODE_ID aCadstarLineCodeID, LAYER_ID aCadstarSheetID, SCH_LAYER_ID aKiCadSchLayerID, const VECTOR2I &aMoveVector={ 0, 0 }, const EDA_ANGLE &aRotation=ANGLE_0, const double &aScalingFactor=1.0, const VECTOR2I &aTransformCentre={ 0, 0 }, const bool &aMirrorInvert=false)
const LIB_SYMBOL * loadSymdef(const SYMDEF_ID &aSymdefID)
int getKiCadUnitNumberFromGate(const GATE_ID &aCadstarGateID)
void loadSymbolFieldAttribute(const ATTRIBUTE_LOCATION &aCadstarAttrLoc, const EDA_ANGLE &aComponentOrientation, bool aIsMirrored, SCH_FIELD *aKiCadField)
int KiCadUnitDivider
Use this value to convert units in this CSA file to KiCad units.
EDA_ANGLE Normalize()
Definition eda_angle.h:229
double AsDegrees() const
Definition eda_angle.h:116
bool IsZero() const
Definition eda_angle.h:136
EDA_ANGLE Normalize180()
Definition eda_angle.h:268
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:135
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:108
EDA_ITEM * GetParent() const
Definition eda_item.h:110
virtual void SetParent(EDA_ITEM *aParent)
Definition eda_item.cpp:89
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:244
SHAPE_POLY_SET & GetPolyShape()
SHAPE_T GetShape() const
Definition eda_shape.h:185
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition eda_shape.h:240
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition eda_shape.h:190
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
void SetFillMode(FILL_T aFill)
virtual void SetPolyShape(const SHAPE_POLY_SET &aShape)
Definition eda_shape.h:427
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:194
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:89
virtual VECTOR2I GetTextSize() const
Definition eda_text.h:282
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:532
virtual const wxString & GetText() const
Return the string associated with the text object.
Definition eda_text.h:110
virtual void SetTextPos(const VECTOR2I &aPoint)
Definition eda_text.cpp:576
virtual int GetTextHeight() const
Definition eda_text.h:288
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:412
virtual int GetTextWidth() const
Definition eda_text.h:285
virtual void SetTextWidth(int aWidth)
Definition eda_text.cpp:554
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
virtual void SetTextThickness(int aWidth)
The TextThickness is that set by the user.
Definition eda_text.cpp:279
virtual void SetTextHeight(int aHeight)
Definition eda_text.cpp:565
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:168
void SetBold(bool aBold)
Set the text to be bold - this will also update the font if needed.
Definition eda_text.cpp:330
virtual int GetTextThickness() const
Definition eda_text.h:149
virtual void SetText(const wxString &aText)
Definition eda_text.cpp:265
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:294
void SetItalic(bool aItalic)
Set the text to be italic - this will also update the font if needed.
Definition eda_text.cpp:302
void SetMultilineAllowed(bool aAllow)
Definition eda_text.cpp:396
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:404
ee_rtree::Iterator begin() const
Return a read/write iterator that points to the first.
Definition sch_rtree.h:261
ee_rtree::Iterator end() const
Return a read/write iterator that points to one past the last element in the EE_RTREE.
Definition sch_rtree.h:269
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:124
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:113
UTF8 Format() const
Definition lib_id.cpp:132
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition lib_id.cpp:205
Define a library symbol object.
Definition lib_symbol.h:114
void SetGlobalPower()
std::vector< const SCH_PIN * > GetGraphicalPins(int aUnit=0, int aBodyStyle=0) const
Graphical pins: Return schematic pin objects as drawn (unexpanded), filtered by unit/body.
void GetFields(std::vector< SCH_FIELD * > &aList, bool aVisibleOnly=false) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
std::vector< struct LIB_SYMBOL_UNIT > GetUnitDrawItems()
Return a list of SCH_ITEM objects separated by unit and convert number.
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
SCH_FIELD & GetFootprintField()
Return reference to the footprint field.
Definition lib_symbol.h:436
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:809
wxString GetName() const override
Definition lib_symbol.h:176
void SetDescription(const wxString &aDescription)
Gets the Description field text value *‍/.
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:428
void RemoveDrawItem(SCH_ITEM *aItem)
Remove draw aItem from list.
void SetFPFilters(const wxArrayString &aFilters)
Definition lib_symbol.h:240
std::vector< SCH_PIN * > GetPinsByNumber(const wxString &aNumber, int aUnit=0, int aBodyStyle=0)
Return all pin objects with the requested pin aNumber.
void AddField(SCH_FIELD *aField)
Add a field.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
virtual void SetName(const wxString &aName)
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition lib_symbol.h:432
ITERATOR_BASE< SCH_ITEM, MULTIVECTOR< SCH_ITEM, FIRST_TYPE_VAL, LAST_TYPE_VAL >, typename ITEM_PTR_VECTOR::iterator > ITERATOR
ITERATOR begin(int aType=UNDEFINED_TYPE)
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
void SetHeightMils(double aHeightInMils)
const VECTOR2D GetSizeIU(double aIUScale) const
Gets the page size in internal units.
Definition page_info.h:173
void SetWidthMils(double aWidthInMils)
Container for project specific data.
Definition project.h:63
virtual std::map< wxString, wxString > & GetTextVars() const
Definition project.cpp:126
Holds all the data relating to one schematic.
Definition schematic.h:90
void SetSize(const VECTOR2I &aSize)
Class for a wire to bus entry.
virtual const wxString & GetText() const override
Return the string associated with the text object.
Definition sch_field.h:128
wxString GetName(bool aUseDefaultName=true) const
Return the field name (not translated).
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
void SetSpinStyle(SPIN_STYLE aSpinStyle) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:162
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition sch_item.cpp:160
int GetUnit() const
Definition sch_item.h:233
void SetLayer(SCH_LAYER_ID aLayer)
Definition sch_item.h:339
virtual void SetUnit(int aUnit)
Definition sch_item.h:232
void SetPosition(const VECTOR2I &aPosition) override
void SetShape(LABEL_FLAG_SHAPE aShape)
Definition sch_label.h:179
void SetPosition(const VECTOR2I &aPosition) override
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:38
void SetStartPoint(const VECTOR2I &aPosition)
Definition sch_line.h:136
void SetLineWidth(const int aSize)
Definition sch_line.cpp:385
VECTOR2I GetEndPoint() const
Definition sch_line.h:144
VECTOR2I GetStartPoint() const
Definition sch_line.h:135
void SetLineStyle(const LINE_STYLE aStyle)
Definition sch_line.cpp:356
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:145
const PAGE_INFO & GetPageSettings() const
Definition sch_screen.h:137
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void AddBusAlias(std::shared_ptr< BUS_ALIAS > aAlias)
Add a bus alias definition.
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition sch_screen.h:138
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition sch_screen.h:115
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void Update(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
Update aItem's bounding box in the tree.
void SetPosition(const VECTOR2I &aPos) override
Definition sch_shape.h:85
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_shape.cpp:98
void AddPoint(const VECTOR2I &aPosition)
VECTOR2I GetPosition() const override
Definition sch_shape.h:84
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
Define a sheet pin (label) used in sheets to create hierarchical schematics.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:44
wxString GetFileName() const
Return the filename corresponding to this sheet.
Definition sch_sheet.h:370
void AddPin(SCH_SHEET_PIN *aSheetPin)
Add aSheetPin to the sheet.
std::vector< SCH_FIELD > & GetFields()
Return a reference to the vector holding the sheet's fields.
Definition sch_sheet.h:87
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this sheet.
VECTOR2I GetSize() const
Definition sch_sheet.h:141
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:139
VECTOR2I GetPosition() const override
Definition sch_sheet.h:490
void SetFields(const std::vector< SCH_FIELD > &aFields)
Set multiple schematic fields.
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
static bool ClassOf(const EDA_ITEM *aItem)
Definition sch_sheet.h:63
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Schematic symbol object.
Definition sch_symbol.h:69
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_symbol.h:915
void UpdatePins()
Updates the cache of SCH_PIN objects for each pin.
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void SetOrientation(int aOrientation)
Compute the new transform matrix based on aOrientation for the symbol which is applied to the current...
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
std::unique_ptr< LIB_SYMBOL > & GetLibSymbolRef()
Definition sch_symbol.h:177
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
VECTOR2I GetPosition() const override
Definition sch_text.h:146
void SetPosition(const VECTOR2I &aPosition) override
Definition sch_text.h:147
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition sch_text.cpp:341
const VECTOR2I & GetArcMid() const
Definition shape_arc.h:116
const VECTOR2I & GetP1() const
Definition shape_arc.h:115
const VECTOR2I & GetP0() const
Definition shape_arc.h:114
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
const SHAPE_LINE_CHAIN Reverse() const
Reverse point order in the line chain.
void SetPoint(int aIndex, const VECTOR2I &aPos)
Move a point to a specific location.
int FindSegment(const VECTOR2I &aP, int aThreshold=1) const
Search for segment containing point aP.
int Intersect(const SEG &aSeg, INTERSECTIONS &aIp) const
Find all intersection points between our line chain and the segment aSeg.
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Replace points with indices in range [start_index, end_index] with a single point aP.
virtual size_t GetPointCount() const override
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
std::vector< INTERSECTION > INTERSECTIONS
const std::vector< VECTOR2I > & CPoints() const
SHAPE_LINE_CHAIN & Outline(int aIndex)
Return the reference to aIndex-th outline in the set.
SPIN_STYLE MirrorX()
Mirror the label spin style across the X axis or simply swaps up and bottom.
SPIN_STYLE MirrorY()
Mirror the label spin style across the Y axis or simply swaps left and right.
SPIN_STYLE RotateCCW()
Simple container to manage line stroke parameters.
virtual void SetShowPinNumbers(bool aShow)
Set or clear the pin number visibility flag.
Definition symbol.h:170
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition symbol.h:164
wxString wx_str() const
Definition utf8.cpp:41
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
#define DEFAULT_WIRE_WIDTH_MILS
The default bus width in mils. (can be changed in preference menu)
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:411
static constexpr EDA_ANGLE ANGLE_90
Definition eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
static constexpr EDA_ANGLE ANGLE_45
Definition eda_angle.h:412
static constexpr EDA_ANGLE ANGLE_270
Definition eda_angle.h:416
static constexpr EDA_ANGLE ANGLE_180
Definition eda_angle.h:415
static constexpr EDA_ANGLE ANGLE_135
Definition eda_angle.h:414
#define IGNORE_PARENT_GROUP
Definition eda_item.h:53
@ NO_FILL
Definition eda_shape.h:60
@ FILLED_WITH_BG_BODYCOLOR
Definition eda_shape.h:62
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:61
static const std::string KiCadSchematicFileExtension
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:455
@ LAYER_DEVICE
Definition layer_ids.h:472
@ LAYER_WIRE
Definition layer_ids.h:458
@ LAYER_NOTES
Definition layer_ids.h:473
@ LAYER_BUS
Definition layer_ids.h:459
MULTIVECTOR< SCH_ITEM, SCH_SHAPE_T, SCH_PIN_T > LIB_ITEMS_CONTAINER
Definition lib_symbol.h:50
This file contains miscellaneous commonly used macros and functions.
#define KI_FALLTHROUGH
The KI_FALLTHROUGH macro is to be used when switch statement cases should purposely fallthrough from ...
Definition macros.h:79
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition mirror.h:41
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
@ VERTEX
An indexed rectangle corner or polygon outline vertex; pairs with CONSTRAINT_MEMBER::m_index.
ELECTRICAL_PINTYPE
The symbol library pin object electrical types used in ERC tests.
Definition pin_type.h:32
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:33
@ PT_OUTPUT
usual output
Definition pin_type.h:34
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:35
@ PT_OPENCOLLECTOR
pin type open collector
Definition pin_type.h:44
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:41
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:39
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:123
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:107
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:114
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:131
@ RPT_SEVERITY_WARNING
@ RPT_SEVERITY_ERROR
@ AUTOPLACE_AUTO
Definition sch_item.h:67
@ L_BIDI
Definition sch_label.h:100
@ L_UNSPECIFIED
Definition sch_label.h:102
@ L_OUTPUT
Definition sch_label.h:99
@ L_INPUT
Definition sch_label.h:98
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
#define SIM_DEVICE_FIELD
Definition sim_model.h:49
#define SIM_PARAMS_FIELD
Definition sim_model.h:53
void wxStringSplit(const wxString &aText, wxArrayString &aStrings, wxChar aSplitter)
Split aString to a string list separated at aSplitter.
bool ReplaceIllegalFileNameChars(std::string &aName, int aReplaceChar)
Checks aName for illegal file name characters.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
LINE_STYLE
Dashed line types.
JUSTIFICATION Justification
Note: Justification has no effect on single lines of text.
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment()" is selected) Bottom Left o...
bool HasLocation
Flag to know if this ATTRIBUTE_VALUE has a location i.e.
Represent a cutout in a closed shape (e.g.
long ScaleRatioNumerator
Documentation symbols can be arbitrarily scaled when added to a design.
long ScaleRatioDenominator
Documentation symbols can be arbitrarily scaled when added to a design.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
LAYER_ID LayerID
Move all objects in the Symdef to this layer.
SYMDEF_ID SymdefID
Normally documentation symbols only have TEXT, FIGURE and TEXT_LOCATION objects which are all drawn o...
long Modifier1
It seems this is related to weight. 400=Normal, 700=Bold.
wxString Name
This is undefined (wxEmptyString) if the net is unnamed.
long SignalNum
This is undefined if the net has been given a name.
bool HidePinNames
Specifies whether to display the pin names/identifier in the schematic symbol or not.
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
Some attributes are defined within the part definition, whilst others are defined in the part.
std::map< PART_DEFINITION_PIN_ID, PIN > Pins
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
Some attributes are defined within the part definition, whilst others are defined in the part itself.
Represent a point in x,y coordinates.
SHAPE_POLY_SET ConvertToPolySet(const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback, int aAccuracy) const
std::vector< CUTOUT > Cutouts
Not Applicable to OPENSHAPE Type.
std::map< FIGURE_ID, FIGURE > Figures
std::map< ATTRIBUTE_ID, TEXT_LOCATION > TextLocations
This contains location of any attributes, including designator position.
POINT Origin
Origin of the component (this is used as the reference point when placing the component in the design...
wxString Alternate
This is in addition to ReferenceName.
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
These attributes might also have a location.
long Width
Defaults to 0 if using system fonts or, if using CADSTAR font, default to equal height (1:1 aspect ra...
ALIGNMENT Alignment
In CADSTAR The default alignment for a TEXT object (when "(No Alignment)" is selected) Bottom Left of...
JUSTIFICATION Justification
Note: has no effect on single lines of text.
< Nodename = "VARIANT" or "VMASTER" (master variant
Represents a vertex in a shape.
SHAPE_ARC BuildArc(const VECTOR2I &aPrevPoint, const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback) const
void AppendToChain(SHAPE_LINE_CHAIN *aChainToAppendTo, const std::function< VECTOR2I(const VECTOR2I &)> aCadstarToKicadPointCallback, int aAccuracy) const
CADSTAR Parts Library (*.lib) model - a data structure describing the contents of the file format.
std::vector< CADSTAR_PART_ENTRY > m_PartEntries
std::string m_ComponentStem
std::map< std::string, std::vector< CADSTAR_PART_PIN > > m_HiddenPins
Pins with an implied electrical connection to a net, not part of any symbol (Note: we probably will n...
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_SchAttributes
Dollar sign ($) line $[!
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_SchAndPcbAttributes
At symbol (@) line [@[!
std::vector< CADSTAR_PART_SYMBOL_ENTRY > m_Symbols
Symbols that form this part.
std::map< std::string, std::string > m_UserAttributes
Star (*) line *<User-defined name> This line is ignored by CADSTAR.
std::map< long, std::string > m_PinNamesMap
Map of pin identifiers to alphanumeric pin names.
std::optional< std::string > m_AcceptancePartName
bool m_PinsVisible
std::optional< std::string > m_Pcb_alternate
std::optional< std::string > m_Version
std::string m_Name
std::optional< std::string > m_Description
std::optional< std::string > m_Number
std::string m_Pcb_component
std::optional< std::string > m_SpiceModel
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_PcbAttributes
Percentage sign (%) line %[!
std::optional< std::string > m_Value
std::map< std::string, CADSTAR_ATTRIBUTE_VALUE > m_PartAttributes
Tilde (~) line ~[!
std::map< long, std::string > m_PinLabelsMap
Map of pin identifiers to alphanumeric pin labels.
std::string m_SymbolName
std::vector< CADSTAR_PART_PIN > m_Pins
std::optional< std::string > m_SymbolAlternateName
TYPE Type
Determines what the associated layer is, whether parent, child or clone.
LAYER_ID LayerID
The sheet block is on (TODO: verify this is true)
LAYER_ID AssocLayerID
Parent or Child linked sheet.
std::map< TERMINAL_ID, TERMINAL > Terminals
LAYER_ID LayerID
Sheet on which bus is located.
std::map< NETELEMENT_ID, DANGLER > Danglers
std::map< NETELEMENT_ID, SYM_TERM > Terminals
std::map< NETELEMENT_ID, BUS_TERM > BusTerminals
std::map< NETELEMENT_ID, BLOCK_TERM > BlockTerminals
std::map< NETELEMENT_ID, JUNCTION_SCH > Junctions
LAYER_ID LayerID
Sheet on which symbol is located.
std::map< ATTRIBUTE_ID, ATTRIBUTE_VALUE > AttributeValues
GATE_ID GateID
The gate this symbol represents within the associated Part.
long ScaleRatioNumerator
Symbols can be arbitrarily scaled in CADSTAR.
std::map< TERMINAL_ID, SYMPINNAME_LABEL > PinNames
Identifier of the pin in the PCB Equivalent to KiCad's Pin Number.
std::map< TERMINAL_ID, PIN_NUM > PinNumbers
This seems to only appear in older designs and is similar to PinNames but only allowing numerical val...
std::map< TERMINAL_ID, PIN_NUM_LABEL_LOC > PinLabelLocations
std::map< TERMINAL_ID, PIN_NUM_LABEL_LOC > PinNumberLocations
std::map< TERMINAL_ID, TERMINAL > Terminals
POINT Position
Pad position within the component's coordinate frame.
@ SYM_ORIENT_270
Definition symbol.h:38
@ SYM_MIRROR_Y
Definition symbol.h:40
@ SYM_ORIENT_180
Definition symbol.h:37
@ SYM_ORIENT_90
Definition symbol.h:36
@ SYM_ORIENT_0
Definition symbol.h:35
@ USER
The field ID hasn't been set yet; field is invalid.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
KIBIS_COMPONENT * comp
KIBIS_PIN * pin
bool cw
VECTOR2I end
int delta
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ GR_TEXT_V_ALIGN_CENTER
@ GR_TEXT_V_ALIGN_TOP
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition trigo.cpp:225
@ SCH_SYMBOL_T
Definition typeinfo.h:169
@ SCH_FIELD_T
Definition typeinfo.h:147
@ SCH_SHAPE_T
Definition typeinfo.h:146
@ SCH_SHEET_PIN_T
Definition typeinfo.h:171
@ SCH_TEXT_T
Definition typeinfo.h:148
@ SCH_PIN_T
Definition typeinfo.h:150
constexpr int sign(T val)
Definition util.h:141
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
constexpr int LexicographicalCompare(const VECTOR2< T > &aA, const VECTOR2< T > &aB)
Definition vector2d.h:632
Definition of file extensions used in Kicad.