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( "" ) );
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 )->SetText( value.value() );
210 };
211
212 addFieldIfHasValue( PartNumberFieldName, aPart.m_Number );
213 addFieldIfHasValue( PartVersionFieldName, aPart.m_Version );
214 addFieldIfHasValue( PartAcceptanceFieldName, aPart.m_AcceptancePartName );
215
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 )->SetText( "SPICE" );
223 addNewFieldToSymbol( SIM_PARAMS_FIELD, retSym )->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 )->SetText( value );
233
234 for( auto& [fieldName, attrValue] : aPart.m_SchAttributes )
235 addNewFieldToSymbol( fieldName, retSym )->SetText( attrValue.m_Value );
236
237 for( auto& [fieldName, attrValue] : aPart.m_PcbAttributes )
238 addNewFieldToSymbol( fieldName, retSym )->SetText( attrValue.m_Value );
239
240 for( auto& [fieldName, attrValue] : aPart.m_SchAndPcbAttributes )
241 addNewFieldToSymbol( fieldName, retSym )->SetText( attrValue.m_Value );
242
243 for( auto& [fieldName, attrValue] : aPart.m_PartAttributes )
244 addNewFieldToSymbol( fieldName, retSym )->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, retSym, 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
304void CADSTAR_SCH_ARCHIVE_LOADER::copySymbolItems( std::unique_ptr<LIB_SYMBOL>& aSourceSym,
305 std::unique_ptr<LIB_SYMBOL>& aDestSym,
306 int aDestUnit, bool aOverrideFields )
307{
308 // Ensure there are no items on the unit we want to load onto
309 for( SCH_ITEM* item : aDestSym->GetUnitDrawItems( aDestUnit, 0 /* aBodyStyle */ ) )
310 aDestSym->RemoveDrawItem( item );
311
312 // Copy all draw items
313 for( SCH_ITEM* newItem : aSourceSym->GetUnitDrawItems( 1, 0 /* aBodyStyle */ ) )
314 {
315 SCH_ITEM* itemCopy = static_cast<SCH_ITEM*>( newItem->Clone() );
316 itemCopy->SetParent( aDestSym.get() );
317 itemCopy->SetUnit( aDestUnit );
318 aDestSym->AddDrawItem( itemCopy );
319 }
320
321 //Copy / override all fields
322 if( aOverrideFields )
323 {
324 std::vector<SCH_FIELD*> fieldsToCopy;
325 aSourceSym->GetFields( fieldsToCopy );
326
327 for( SCH_FIELD* templateField : fieldsToCopy )
328 {
329 SCH_FIELD* appliedField = addNewFieldToSymbol( templateField->GetName(), aDestSym );
330 templateField->Copy( appliedField );
331 }
332 }
333}
334
335
337{
338 wxCHECK( aSchematic, /* void */ );
339
341 m_progressReporter->SetNumPhases( 3 ); // (0) Read file, (1) Parse file, (2) Load file
342
343 Parse();
344
345 checkDesignLimits(); // Throws if error found
346
347 // Assume the center at 0,0 since we are going to be translating the design afterwards anyway
348 m_designCenter = { 0, 0 };
349
350 m_schematic = aSchematic;
351 m_rootSheet = aRootSheet;
352
354 {
355 m_progressReporter->BeginPhase( 2 );
356 long numSteps = 11; // one step for each of below functions + one at the end of import
357
358 // Step 4 is by far the longest - add granularity in reporting
359 numSteps += Parts.PartDefinitions.size();
360
361 m_progressReporter->SetMaxProgress( numSteps );
362 }
363
364 loadTextVariables(); // Load text variables right at the start to ensure bounding box
365 // calculations work correctly for text items
366 checkPoint(); // Step 1
367 loadSheets();
368 checkPoint(); // Step 2
370 checkPoint(); // Step 3
372 checkPoint(); // Step 4, Subdivided into extra steps
374 checkPoint(); // Step 5
375 loadBusses();
376 checkPoint(); // Step 6
377 loadNets();
378 checkPoint(); // Step 7
379 loadFigures();
380 checkPoint(); // Step 8
381 loadTexts();
382 checkPoint(); // Step 9
384 checkPoint(); // Step 10
385
386 if( Schematic.VariantHierarchy.Variants.size() > 0 )
387 {
388 m_reporter->Report( wxString::Format( _( "The CADSTAR design contains variants which has "
389 "no KiCad equivalent. Only the master variant "
390 "('%s') was loaded." ),
391 Schematic.VariantHierarchy.Variants.at( "V0" ).Name ),
393 }
394
395 if( Schematic.Groups.size() > 0 )
396 {
397 m_reporter->Report( _( "The CADSTAR design contains grouped items which has no KiCad "
398 "equivalent. Any grouped items have been ungrouped." ),
400 }
401
402 if( Schematic.ReuseBlocks.size() > 0 )
403 {
404 m_reporter->Report( _( "The CADSTAR design contains re-use blocks which has no KiCad "
405 "equivalent. The re-use block information has been discarded during "
406 "the import." ),
408 }
409
410
411 // For all sheets, center all elements and re calculate the page size:
412 for( std::pair<LAYER_ID, SCH_SHEET*> sheetPair : m_sheetMap )
413 {
414 SCH_SHEET* sheet = sheetPair.second;
415
416 // Calculate the new sheet size.
417 BOX2I sheetBoundingBox;
418
419 for( SCH_ITEM* item : sheet->GetScreen()->Items() )
420 {
421 BOX2I bbox;
422
423 // Only use the visible fields of the symbols to calculate their bounding box
424 // (hidden fields could be very long and artificially enlarge the sheet bounding box)
425 if( item->Type() == SCH_SYMBOL_T )
426 {
427 SCH_SYMBOL* comp = static_cast<SCH_SYMBOL*>( item );
428 bbox = comp->GetBodyAndPinsBoundingBox();
429
430 for( const SCH_FIELD& field : comp->GetFields() )
431 {
432 if( field.IsVisible() )
433 bbox.Merge( field.GetBoundingBox() );
434 }
435 }
436 else if( item->Type() == SCH_TEXT_T )
437 {
438 SCH_TEXT* txtItem = static_cast<SCH_TEXT*>( item );
439 wxString txt = txtItem->GetText();
440
441 if( txt.Contains( "${" ) )
442 continue; // We can't calculate bounding box of text items with variables
443 else
444 bbox = txtItem->GetBoundingBox();
445 }
446 else
447 {
448 bbox = item->GetBoundingBox();
449 }
450
451 sheetBoundingBox.Merge( bbox );
452 }
453
454 // Find the screen grid of the original CADSTAR design
455 int grid = Assignments.Grids.ScreenGrid.Param1;
456
457 if( Assignments.Grids.ScreenGrid.Type == GRID_TYPE::FRACTIONALGRID )
458 grid = grid / Assignments.Grids.ScreenGrid.Param2;
459 else if( Assignments.Grids.ScreenGrid.Param2 > grid )
460 grid = Assignments.Grids.ScreenGrid.Param2;
461
463
464 auto roundToNearestGrid =
465 [&]( int aNumber ) -> int
466 {
467 int error = aNumber % grid;
468 int absError = sign( error ) * error;
469
470 if( absError > ( grid / 2 ) )
471 return aNumber + ( sign( error ) * grid ) - error;
472 else
473 return aNumber - error;
474 };
475
476 // When exporting to pdf, CADSTAR applies a margin of 3percent of the longest dimension (height
477 // or width) to all 4 sides (top, bottom, left right). For the import, we are also rounding
478 // the margin to the nearest grid, ensuring all items remain on the grid.
479 VECTOR2I targetSheetSize = sheetBoundingBox.GetSize();
480 int longestSide = std::max( targetSheetSize.x, targetSheetSize.y );
481 int margin = ( (double) longestSide * 0.03 );
482 margin = roundToNearestGrid( margin );
483 targetSheetSize += margin * 2;
484
485 // Update page size always
486 PAGE_INFO pageInfo = sheet->GetScreen()->GetPageSettings();
487 pageInfo.SetWidthMils( schIUScale.IUToMils( targetSheetSize.x ) );
488 pageInfo.SetHeightMils( schIUScale.IUToMils( targetSheetSize.y ) );
489
490 // Set the new sheet size.
491 sheet->GetScreen()->SetPageSettings( pageInfo );
492
493 VECTOR2I pageSizeIU = sheet->GetScreen()->GetPageSettings().GetSizeIU( schIUScale.IU_PER_MILS );
494 VECTOR2I sheetcentre( pageSizeIU.x / 2, pageSizeIU.y / 2 );
495 VECTOR2I itemsCentre = sheetBoundingBox.Centre();
496
497 // round the translation to nearest point on the grid
498 VECTOR2I translation = sheetcentre - itemsCentre;
499 translation.x = roundToNearestGrid( translation.x );
500 translation.y = roundToNearestGrid( translation.y );
501
502 // Translate the items.
503 std::vector<SCH_ITEM*> allItems;
504
505 std::copy( sheet->GetScreen()->Items().begin(), sheet->GetScreen()->Items().end(),
506 std::back_inserter( allItems ) );
507
508 for( SCH_ITEM* item : allItems )
509 {
510 item->Move( translation );
511 item->ClearFlags();
512 sheet->GetScreen()->Update( item );
513 }
514 }
515
516 checkPoint();
517
518 m_reporter->Report( _( "CADSTAR fonts are different to the ones in KiCad. This will likely "
519 "result in alignment issues. Please review the imported text elements "
520 "carefully and correct manually if required." ),
522
523 m_reporter->Report( _( "The CADSTAR design has been imported successfully.\n"
524 "Please review the import errors and warnings (if any)." ) );
525}
526
527
529{
530 LONGPOINT designLimit = Assignments.Settings.DesignLimit;
531
532 //Note: can't use getKiCadPoint() due VECTOR2I being int - need long long to make the check
533 long long designSizeXkicad = (long long) designLimit.x / KiCadUnitDivider;
534 long long designSizeYkicad = (long long) designLimit.y / KiCadUnitDivider;
535
536 // Max size limited by the positive dimension of VECTOR2I (which is an int)
537 constexpr long long maxDesignSizekicad = std::numeric_limits<int>::max();
538
539 if( designSizeXkicad > maxDesignSizekicad || designSizeYkicad > maxDesignSizekicad )
540 {
541 THROW_IO_ERROR( wxString::Format(
542 _( "The design is too large and cannot be imported into KiCad. \n"
543 "Please reduce the maximum design size in CADSTAR by navigating to: \n"
544 "Design Tab -> Properties -> Design Options -> Maximum Design Size. \n"
545 "Current Design size: %.2f, %.2f millimeters. \n" //format:allow
546 "Maximum permitted design size: %.2f, %.2f millimeters.\n" ), //format:allow
547 (double) designSizeXkicad / SCH_IU_PER_MM,
548 (double) designSizeYkicad / SCH_IU_PER_MM,
549 (double) maxDesignSizekicad / SCH_IU_PER_MM,
550 (double) maxDesignSizekicad / SCH_IU_PER_MM ) );
551 }
552}
553
554
556{
557 const std::vector<LAYER_ID>& orphanSheets = findOrphanSheets();
558 SCH_SHEET_PATH rootPath;
559 rootPath.push_back( m_rootSheet );
560 rootPath.SetPageNumber( wxT( "1" ) );
561
562 if( orphanSheets.size() > 1 )
563 {
564 int x = 1;
565 int y = 1;
566
567 for( LAYER_ID sheetID : orphanSheets )
568 {
569 VECTOR2I pos( x * schIUScale.MilsToIU( 1000 ), y * schIUScale.MilsToIU( 1000 ) );
570 VECTOR2I siz( schIUScale.MilsToIU( 1000 ), schIUScale.MilsToIU( 1000 ) );
571
572 loadSheetAndChildSheets( sheetID, pos, siz, rootPath );
573
574 x += 2;
575
576 if( x > 10 ) // start next row
577 {
578 x = 1;
579 y += 2;
580 }
581 }
582 }
583 else if( orphanSheets.size() > 0 )
584 {
585 LAYER_ID rootSheetID = orphanSheets.at( 0 );
586
587 wxFileName loadedFilePath = wxFileName( Filename );
588
589 std::string filename = wxString::Format( "%s_%02d", loadedFilePath.GetName(),
590 getSheetNumber( rootSheetID ) )
591 .ToStdString();
592 ReplaceIllegalFileNameChars( filename );
593 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
594
595 wxFileName fn( m_schematic->Project().GetProjectPath() + filename );
596 m_rootSheet->GetScreen()->SetFileName( fn.GetFullPath() );
597
598 m_sheetMap.insert( { rootSheetID, m_rootSheet } );
599 loadChildSheets( rootSheetID, rootPath );
600 }
601 else if( Header.Format.Type == "SYMBOL" )
602 {
603 THROW_IO_ERROR( _( "The selected file is a CADSTAR symbol library. It does not contain a "
604 "schematic design so cannot be imported/opened in this way." ) );
605 }
606 else
607 {
608 THROW_IO_ERROR( _( "The CADSTAR schematic might be corrupt: there is no root sheet." ) );
609 }
610}
611
612
614{
615 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
616 {
617 BLOCK& block = blockPair.second;
618 LAYER_ID sheetID = "";
619
620 if( block.Type == BLOCK::TYPE::PARENT )
621 sheetID = block.LayerID;
622 else if( block.Type == BLOCK::TYPE::CHILD )
623 sheetID = block.AssocLayerID;
624 else
625 continue;
626
627 if( m_sheetMap.find( sheetID ) != m_sheetMap.end() )
628 {
629 SCH_SHEET* sheet = m_sheetMap.at( sheetID );
630
631 for( std::pair<TERMINAL_ID, TERMINAL> termPair : block.Terminals )
632 {
633 TERMINAL term = termPair.second;
634 wxString name = "YOU SHOULDN'T SEE THIS TEXT. THIS IS A BUG.";
635
636 SCH_HIERLABEL* sheetPin = nullptr;
637
638 if( block.Type == BLOCK::TYPE::PARENT )
639 sheetPin = new SCH_HIERLABEL();
640 else if( block.Type == BLOCK::TYPE::CHILD )
641 sheetPin = new SCH_SHEET_PIN( sheet );
642
643 sheetPin->SetText( name );
645 sheetPin->SetSpinStyle( getSpinStyle( term.OrientAngle, false ) );
646 sheetPin->SetPosition( getKiCadPoint( term.Position ) );
647
648 if( sheetPin->Type() == SCH_SHEET_PIN_T )
649 sheet->AddPin( (SCH_SHEET_PIN*) sheetPin );
650 else
651 sheet->GetScreen()->Append( sheetPin );
652
653 BLOCK_PIN_ID blockPinID = std::make_pair( block.ID, term.ID );
654 m_sheetPinMap.insert( { blockPinID, sheetPin } );
655 }
656 }
657 }
658}
659
660
662{
663 for( std::pair<PART_ID, PART> partPair : Parts.PartDefinitions )
664 {
665 PART_ID partID = partPair.first;
666 PART part = partPair.second;
667
668 wxString escapedPartName = EscapeString( part.Name, CTX_LIBID );
669 LIB_SYMBOL* kiSym = new LIB_SYMBOL( escapedPartName );
670
671 kiSym->SetUnitCount( part.Definition.GateSymbols.size(), true );
672 bool ok = true;
673
674 for( std::pair<GATE_ID, PART::DEFINITION::GATE> gatePair : part.Definition.GateSymbols )
675 {
676 GATE_ID gateID = gatePair.first;
677 PART::DEFINITION::GATE gate = gatePair.second;
678 SYMDEF_ID symbolID = getSymDefFromName( gate.Name, gate.Alternate );
679
680 if( symbolID.IsEmpty() )
681 {
682 m_reporter->Report( wxString::Format( _( "Part definition '%s' references symbol "
683 "'%s' (alternate '%s') which could not be "
684 "found in the symbol library. The part has "
685 "not been loaded into the KiCad library." ),
686 part.Name,
687 gate.Name,
688 gate.Alternate ),
690
691 ok = false;
692 break;
693 }
694
695 m_partSymbolsMap.insert( { { partID, gateID }, symbolID } );
696 loadSymbolGateAndPartFields( symbolID, part, gateID, kiSym );
697 }
698
699 if( ok && part.Definition.GateSymbols.size() != 0 )
700 {
701 m_loadedSymbols.push_back( kiSym );
702 }
703 else
704 {
705 if( part.Definition.GateSymbols.size() == 0 )
706 {
707 m_reporter->Report( wxString::Format( _( "Part definition '%s' has an incomplete "
708 "definition (no symbol definitions are "
709 "associated with it). The part has not "
710 "been loaded into the KiCad library." ),
711 part.Name ),
713 }
714
715 // Don't save in the library, but still keep it cached as some of the units might have
716 // been loaded correctly (saving us time later on), plus the part definition contains
717 // the part name, which is important to load
718 }
719
720 m_partMap.insert( { partID, kiSym } );
721
722 checkPoint();
723 }
724}
725
726
728{
729 for( std::pair<SYMBOL_ID, SYMBOL> symPair : Schematic.Symbols )
730 {
731 SYMBOL sym = symPair.second;
732
733 if( !sym.VariantID.empty() && sym.VariantParentSymbolID != sym.ID )
734 continue; // Only load master Variant
735
736 if( sym.IsComponent )
737 {
738 if( m_partMap.find( sym.PartRef.RefID ) == m_partMap.end() )
739 {
740 m_reporter->Report( wxString::Format( _( "Symbol '%s' references part '%s' which "
741 "could not be found in the library. The "
742 "symbol was not loaded" ),
744 sym.PartRef.RefID ),
746
747 continue;
748 }
749
750 if( sym.GateID.IsEmpty() )
751 sym.GateID = wxT( "A" ); // Assume Gate "A" if unspecified
752
753 PART_GATE_ID partSymbolID = { sym.PartRef.RefID, sym.GateID };
754 LIB_SYMBOL* kiSym = m_partMap.at( sym.PartRef.RefID );
755 bool copy = false;
756
757 // The symbol definition in the part either does not exist for this gate number
758 // or is different to the symbol instance. We need to reload the gate for this
759 // symbol
760 if( m_partSymbolsMap.find( partSymbolID ) == m_partSymbolsMap.end()
761 || m_partSymbolsMap.at( partSymbolID ) != sym.SymdefID )
762 {
763 kiSym = new LIB_SYMBOL( *kiSym ); // Make a copy
764 copy = true;
765 const PART& part = Parts.PartDefinitions.at( sym.PartRef.RefID );
766 loadSymbolGateAndPartFields( sym.SymdefID, part, sym.GateID, kiSym );
767 }
768
769 LIB_SYMBOL* scaledPart = getScaledLibPart( kiSym, sym.ScaleRatioNumerator,
771
772 EDA_ANGLE symOrient = ANGLE_0;
773 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, symOrient );
774
775 delete scaledPart;
776
777 if( copy )
778 delete kiSym;
779
780 SCH_FIELD* refField = symbol->GetField( FIELD_T::REFERENCE );
781
782 sym.ComponentRef.Designator.Replace( wxT( "\n" ), wxT( "\\n" ) );
783 sym.ComponentRef.Designator.Replace( wxT( "\r" ), wxT( "\\r" ) );
784 sym.ComponentRef.Designator.Replace( wxT( "\t" ), wxT( "\\t" ) );
785 sym.ComponentRef.Designator.Replace( wxT( " " ), wxT( "_" ) );
786
787 refField->SetText( sym.ComponentRef.Designator );
788 loadSymbolFieldAttribute( sym.ComponentRef.AttrLoc, symOrient, sym.Mirror, refField );
789
790 if( sym.HasPartRef )
791 {
792 SCH_FIELD* partField = symbol->GetField( PartNameFieldName );
793
794 if( !partField )
795 partField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, PartNameFieldName ) );
796
797 wxASSERT( partField->GetName() == PartNameFieldName );
798
799 wxString partname = getPart( sym.PartRef.RefID ).Name;
800 partname.Replace( wxT( "\n" ), wxT( "\\n" ) );
801 partname.Replace( wxT( "\r" ), wxT( "\\r" ) );
802 partname.Replace( wxT( "\t" ), wxT( "\\t" ) );
803 partField->SetText( partname );
804
805 loadSymbolFieldAttribute( sym.PartRef.AttrLoc, symOrient, sym.Mirror, partField );
806
807 partField->SetVisible( SymbolPartNameColor.IsVisible );
808 }
809
810 for( auto& attr : sym.AttributeValues )
811 {
812 ATTRIBUTE_VALUE attrVal = attr.second;
813
814 if( attrVal.HasLocation )
815 {
816 wxString attrName = getAttributeName( attrVal.AttributeID );
817 SCH_FIELD* attrField = symbol->GetField( attrName );
818
819 if( !attrField )
820 attrField = symbol->AddField( SCH_FIELD( symbol, FIELD_T::USER, attrName ) );
821
822 wxASSERT( attrField->GetName() == attrName );
823
824 attrVal.Value.Replace( wxT( "\n" ), wxT( "\\n" ) );
825 attrVal.Value.Replace( wxT( "\r" ), wxT( "\\r" ) );
826 attrVal.Value.Replace( wxT( "\t" ), wxT( "\\t" ) );
827 attrField->SetText( attrVal.Value );
828
829 loadSymbolFieldAttribute( attrVal.AttributeLocation, symOrient, sym.Mirror,
830 attrField );
831 attrField->SetVisible( isAttributeVisible( attrVal.AttributeID ) );
832 }
833 }
834 }
835 else if( sym.IsSymbolVariant )
836 {
837 if( Library.SymbolDefinitions.find( sym.SymdefID ) == Library.SymbolDefinitions.end() )
838 {
839 THROW_IO_ERROR( wxString::Format( _( "Symbol ID '%s' references library symbol "
840 "'%s' which could not be found in the "
841 "library. Did you export all items of the "
842 "design?" ),
843 sym.ID,
844 sym.PartRef.RefID ) );
845 }
846
847 SYMDEF_SCM libSymDef = Library.SymbolDefinitions.at( sym.SymdefID );
848
849 if( libSymDef.Terminals.size() != 1 )
850 {
851 THROW_IO_ERROR( wxString::Format( _( "Symbol ID '%s' is a signal reference or "
852 "global signal but it has too many pins. The "
853 "expected number of pins is 1 but %d were "
854 "found." ),
855 sym.ID,
856 libSymDef.Terminals.size() ) );
857 }
858
859 if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::GLOBALSIGNAL )
860 {
861 SYMDEF_ID symID = sym.SymdefID;
862 LIB_SYMBOL* kiPart = nullptr;
863
864 // In CADSTAR "GlobalSignal" is a special type of symbol which defines
865 // a Power Symbol. The "Alternate" name defines the default net name of
866 // the power symbol but this can be overridden in the design itself.
867 wxString libraryNetName = Library.SymbolDefinitions.at( symID ).Alternate;
868
869 // Name of the net that the symbol instance in CADSTAR refers to:
870 wxString symbolInstanceNetName = sym.SymbolVariant.Reference;
871 symbolInstanceNetName = EscapeString( symbolInstanceNetName, CTX_LIBID );
872
873 // Name of the symbol we will use for saving the part in KiCad
874 // Note: In CADSTAR all power symbols will start have the reference name be
875 // "GLOBALSIGNAL" followed by the default net name, so it makes sense to save
876 // the symbol in KiCad as the default net name as well.
877 wxString libPartName = libraryNetName;
878
879 // In CADSTAR power symbol instances can refer to a different net to that defined
880 // in the library. This causes problems in KiCad v6 as it breaks connectivity when
881 // the user decides to update all symbols from library. We handle this by creating
882 // individual versions of the power symbol for each net name.
883 if( libPartName != symbolInstanceNetName )
884 {
885 libPartName += wxT( " (" ) + symbolInstanceNetName + wxT( ")" );
886 }
887
888 if( m_powerSymLibMap.find( libPartName ) == m_powerSymLibMap.end() )
889 {
890 const LIB_SYMBOL* templatePart = loadSymdef( symID );
891 wxCHECK( templatePart, /*void*/ );
892
893 kiPart = new LIB_SYMBOL( *templatePart );
894 kiPart->SetGlobalPower();
895 kiPart->SetName( libPartName );
896 kiPart->GetValueField().SetText( symbolInstanceNetName );
897 kiPart->SetShowPinNames( false );
898 kiPart->SetShowPinNumbers( false );
899
900 std::vector<SCH_PIN*> pins = kiPart->GetGraphicalPins( 0, 0 );
901 wxCHECK( pins.size() == 1, /*void*/ );
902
903 pins.at( 0 )->SetType( ELECTRICAL_PINTYPE::PT_POWER_IN );
904 pins.at( 0 )->SetName( symbolInstanceNetName );
905
906 if( libSymDef.TextLocations.find( SIGNALNAME_ORIGIN_ATTRID )
907 != libSymDef.TextLocations.end() )
908 {
909 TEXT_LOCATION& txtLoc =
911
912 VECTOR2I valPos = getKiCadLibraryPoint( txtLoc.Position, libSymDef.Origin );
913
914 kiPart->GetValueField().SetPosition( valPos );
915 kiPart->GetValueField().SetVisible( true );
916 }
917 else
918 {
919 kiPart->GetValueField().SetVisible( false );
920 }
921
922 kiPart->GetReferenceField().SetText( "#PWR" );
923 kiPart->GetReferenceField().SetVisible( false );
924 m_loadedSymbols.push_back( kiPart );
925 m_powerSymLibMap.insert( { libPartName, kiPart } );
926 }
927 else
928 {
929 kiPart = m_powerSymLibMap.at( libPartName );
930 wxASSERT( kiPart->GetValueField().GetText() == symbolInstanceNetName );
931 }
932
933 LIB_SYMBOL* scaledPart = getScaledLibPart( kiPart, sym.ScaleRatioNumerator,
935
936 EDA_ANGLE returnedOrient = ANGLE_0;
937 SCH_SYMBOL* symbol = loadSchematicSymbol( sym, *scaledPart, returnedOrient );
938 m_powerSymMap.insert( { sym.ID, symbol } );
939
940 delete scaledPart;
941 }
942 else if( sym.SymbolVariant.Type == SYMBOLVARIANT::TYPE::SIGNALREF )
943 {
944 // There should only be one pin and we'll use that to set the position
945 TERMINAL& symbolTerminal = libSymDef.Terminals.begin()->second;
946 VECTOR2I terminalPosOffset = symbolTerminal.Position - libSymDef.Origin;
947 EDA_ANGLE rotate = getAngle( sym.OrientAngle );
948
949 if( sym.Mirror )
950 rotate += ANGLE_180;
951
952 RotatePoint( terminalPosOffset, -rotate );
953
954 SCH_GLOBALLABEL* netLabel = new SCH_GLOBALLABEL;
955 netLabel->SetPosition( getKiCadPoint( (VECTOR2I)sym.Origin + terminalPosOffset ) );
956 netLabel->SetText( "***UNKNOWN NET****" ); // This should be later updated when we load the netlist
957 netLabel->SetTextSize( VECTOR2I( schIUScale.MilsToIU( 50 ), schIUScale.MilsToIU( 50 ) ) );
958
959 SYMDEF_SCM symbolDef = Library.SymbolDefinitions.at( sym.SymdefID );
960
961 if( symbolDef.TextLocations.count( LINK_ORIGIN_ATTRID ) )
962 {
963 TEXT_LOCATION linkOrigin = symbolDef.TextLocations.at( LINK_ORIGIN_ATTRID );
964 applyTextSettings( netLabel, linkOrigin.TextCodeID, linkOrigin.Alignment,
965 linkOrigin.Justification );
966 }
967
968 netLabel->SetSpinStyle( getSpinStyle( sym.OrientAngle, sym.Mirror ) );
969
970 if( libSymDef.Alternate.Lower().Contains( "in" ) )
972 else if( libSymDef.Alternate.Lower().Contains( "bi" ) )
974 else if( libSymDef.Alternate.Lower().Contains( "out" ) )
976 else
978
979 SCH_SCREEN* screen = m_sheetMap.at( sym.LayerID )->GetScreen();
980
981 // autoplace intersheet refs
982 netLabel->AutoplaceFields( screen, AUTOPLACE_AUTO );
983
984 screen->Append( netLabel );
985 m_globalLabelsMap.insert( { sym.ID, netLabel } );
986 }
987 else
988 {
989 wxASSERT_MSG( false, "Unknown Symbol Variant." );
990 }
991 }
992 else
993 {
994 m_reporter->Report( wxString::Format( _( "Symbol ID '%s' is of an unknown type. It is "
995 "neither a symbol or a net power / symbol. "
996 "The symbol was not loaded." ),
997 sym.ID ),
999 }
1000
1001 if( sym.ScaleRatioDenominator != 1 || sym.ScaleRatioNumerator != 1 )
1002 {
1003 wxString symbolName = sym.ComponentRef.Designator;
1004
1005 if( symbolName.empty() )
1006 symbolName = wxString::Format( "ID: %s", sym.ID );
1007 else
1008 symbolName += sym.GateID;
1009
1010 m_reporter->Report( wxString::Format( _( "Symbol '%s' is scaled in the original "
1011 "CADSTAR schematic but this is not supported "
1012 "in KiCad. When the symbol is reloaded from "
1013 "the library, it will revert to the original "
1014 "1:1 scale." ),
1015 symbolName,
1016 sym.PartRef.RefID ),
1018 }
1019 }
1020}
1021
1022
1024{
1025 for( std::pair<BUS_ID, BUS> busPair : Schematic.Buses )
1026 {
1027 BUS bus = busPair.second;
1028 bool firstPt = true;
1029 VERTEX last;
1030
1031 if( bus.LayerID != wxT( "NO_SHEET" ) )
1032 {
1033 SCH_SCREEN* screen = m_sheetMap.at( bus.LayerID )->GetScreen();
1034 std::shared_ptr<BUS_ALIAS> kiBusAlias = std::make_shared<BUS_ALIAS>();
1035
1036 kiBusAlias->SetName( bus.Name );
1037 screen->AddBusAlias( kiBusAlias );
1038 m_busesMap.insert( { bus.ID, kiBusAlias } );
1039
1040 SCH_LABEL* label = new SCH_LABEL();
1041
1042 wxString busname = HandleTextOverbar( bus.Name );
1043
1044 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1045 label->SetVisible( true );
1046 screen->Append( label );
1047
1048 SHAPE_LINE_CHAIN busLineChain; // to compute nearest segment to bus label
1049
1050 for( const VERTEX& cur : bus.Shape.Vertices )
1051 {
1052 busLineChain.Append( getKiCadPoint( cur.End ) );
1053
1054 if( firstPt )
1055 {
1056 last = cur;
1057 firstPt = false;
1058
1059 if( !bus.HasBusLabel )
1060 {
1061 // Add a bus label on the starting point if the original CADSTAR design
1062 // does not have an explicit label
1063 label->SetPosition( getKiCadPoint( last.End ) );
1064 }
1065
1066 continue;
1067 }
1068
1069
1070 SCH_LINE* kiBus = new SCH_LINE();
1071
1072 kiBus->SetStartPoint( getKiCadPoint( last.End ) );
1073 kiBus->SetEndPoint( getKiCadPoint( cur.End ) );
1074 kiBus->SetLayer( LAYER_BUS );
1075 kiBus->SetLineWidth( getLineThickness( bus.LineCodeID ) );
1076 screen->Append( kiBus );
1077
1078 last = cur;
1079 }
1080
1081 if( bus.HasBusLabel )
1082 {
1083 //lets find the closest point in the busline to the label
1084 VECTOR2I busLabelLoc = getKiCadPoint( bus.BusLabel.Position );
1085 VECTOR2I nearestPt = busLineChain.NearestPoint( busLabelLoc );
1086
1087 label->SetPosition( nearestPt );
1088
1090 bus.BusLabel.Justification );
1091
1092 // Re-set bus name as it might have been "double-escaped" after applyTextSettings
1093 label->SetText( wxT( "{" ) + busname + wxT( "}" ) );
1094
1095 // Note orientation of the bus label will be determined in loadNets
1096 // (the position of the wire will determine how best to place the bus label)
1097 }
1098 }
1099 }
1100}
1101
1102
1104{
1105 for( std::pair<NET_ID, NET_SCH> netPair : Schematic.Nets )
1106 {
1107 NET_SCH net = netPair.second;
1108 wxString netName = net.Name;
1109 std::map<NETELEMENT_ID, SCH_LABEL*> netlabels;
1110
1111 if( netName.IsEmpty() )
1112 netName = wxString::Format( "$%ld", net.SignalNum );
1113
1114 netName = HandleTextOverbar( netName );
1115
1116 for( std::pair<NETELEMENT_ID, NET_SCH::SYM_TERM> terminalPair : net.Terminals )
1117 {
1118 NET_SCH::SYM_TERM netTerm = terminalPair.second;
1119
1120 if( m_powerSymMap.find( netTerm.SymbolID ) != m_powerSymMap.end() )
1121 {
1122 SCH_FIELD* val = m_powerSymMap.at( netTerm.SymbolID )->GetField( FIELD_T::VALUE );
1123 val->SetText( netName );
1124 val->SetBold( false );
1125 val->SetVisible( false );
1126
1127 if( netTerm.HasNetLabel )
1128 {
1129 val->SetVisible( true );
1130 val->SetPosition( getKiCadPoint( netTerm.NetLabel.Position ) );
1131
1132 applyTextSettings( val, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1133 netTerm.NetLabel.Justification, netTerm.NetLabel.OrientAngle,
1134 netTerm.NetLabel.Mirror );
1135 }
1136 }
1137 else if( m_globalLabelsMap.find( netTerm.SymbolID ) != m_globalLabelsMap.end() )
1138 {
1139 m_globalLabelsMap.at( netTerm.SymbolID )->SetText( netName );
1140
1141 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1142
1143 if( m_sheetMap.count( sheet ) )
1144 {
1145 SCH_SCREEN* screen = m_sheetMap.at( sheet )->GetScreen();
1146
1147 // autoplace intersheet refs again since we've changed the name
1148 m_globalLabelsMap.at( netTerm.SymbolID )->AutoplaceFields( screen, AUTOPLACE_AUTO );
1149 }
1150 }
1151 else if( !net.Name.IsEmpty() && Schematic.Symbols.count( netTerm.SymbolID )
1152 && netTerm.HasNetLabel )
1153 {
1154 // This is a named net that connects to a schematic symbol pin - we need to put a label
1155 SCH_LABEL* label = new SCH_LABEL();
1156 label->SetText( netName );
1157
1158 POINT pinLocation = getLocationOfNetElement( net, netTerm.ID );
1159 label->SetPosition( getKiCadPoint( pinLocation ) );
1160 label->SetVisible( true );
1161
1162 applyTextSettings( label, netTerm.NetLabel.TextCodeID, netTerm.NetLabel.Alignment,
1163 netTerm.NetLabel.Justification );
1164
1165 netlabels.insert( { netTerm.ID, label } );
1166
1167 LAYER_ID sheet = Schematic.Symbols.at( netTerm.SymbolID ).LayerID;
1168 m_sheetMap.at( sheet )->GetScreen()->Append( label );
1169 }
1170 }
1171
1172 auto getHierarchicalLabel =
1173 [&]( const NETELEMENT_ID& aNode ) -> SCH_HIERLABEL*
1174 {
1175 if( aNode.Contains( "BLKT" ) )
1176 {
1177 NET_SCH::BLOCK_TERM blockTerm = net.BlockTerminals.at( aNode );
1178 BLOCK_PIN_ID blockPinID = std::make_pair( blockTerm.BlockID,
1179 blockTerm.TerminalID );
1180
1181 if( m_sheetPinMap.find( blockPinID ) != m_sheetPinMap.end() )
1182 return m_sheetPinMap.at( blockPinID );
1183 }
1184
1185 return nullptr;
1186 };
1187
1188 //Add net name to all hierarchical pins (block terminals in CADSTAR)
1189 for( std::pair<NETELEMENT_ID, NET_SCH::BLOCK_TERM> blockPair : net.BlockTerminals )
1190 {
1191 SCH_HIERLABEL* label = getHierarchicalLabel( blockPair.first );
1192
1193 if( label )
1194 label->SetText( netName );
1195 }
1196
1197 // Load all bus entries and add net label if required
1198 for( std::pair<NETELEMENT_ID, NET_SCH::BUS_TERM> busPair : net.BusTerminals )
1199 {
1200 NET_SCH::BUS_TERM busTerm = busPair.second;
1201 BUS bus = Schematic.Buses.at( busTerm.BusID );
1202
1203 if( !alg::contains( m_busesMap.at( bus.ID )->Members(), netName ) )
1204 m_busesMap.at( bus.ID )->AddMember( netName );
1205
1206 SCH_BUS_WIRE_ENTRY* busEntry =
1207 new SCH_BUS_WIRE_ENTRY( getKiCadPoint( busTerm.FirstPoint ), false );
1208
1209 VECTOR2I size =
1210 getKiCadPoint( busTerm.SecondPoint ) - getKiCadPoint( busTerm.FirstPoint );
1211 busEntry->SetSize( VECTOR2I( size.x, size.y ) );
1212
1213 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( busEntry );
1214
1215 // Always add a label at bus terminals to ensure connectivity.
1216 // If the original design does not have a label, just make it very small
1217 // to keep connectivity but make the design look visually similar to
1218 // the original.
1219 SCH_LABEL* label = new SCH_LABEL();
1220 label->SetText( netName );
1221 label->SetPosition( getKiCadPoint( busTerm.SecondPoint ) );
1222 label->SetVisible( true );
1223
1224 if( busTerm.HasNetLabel )
1225 {
1226 applyTextSettings( label, busTerm.NetLabel.TextCodeID, busTerm.NetLabel.Alignment,
1227 busTerm.NetLabel.Justification );
1228 }
1229 else
1230 {
1232 }
1233
1234 netlabels.insert( { busTerm.ID, label } );
1235 m_sheetMap.at( bus.LayerID )->GetScreen()->Append( label );
1236 }
1237
1238 for( std::pair<NETELEMENT_ID, NET_SCH::DANGLER> danglerPair : net.Danglers )
1239 {
1240 NET_SCH::DANGLER dangler = danglerPair.second;
1241
1242 SCH_LABEL* label = new SCH_LABEL();
1243 label->SetPosition( getKiCadPoint( dangler.Position ) );
1244 label->SetVisible( true );
1245
1246 if( dangler.HasNetLabel )
1247 {
1248 applyTextSettings( label, dangler.NetLabel.TextCodeID, dangler.NetLabel.Alignment,
1249 dangler.NetLabel.Justification );
1250 }
1251
1252 label->SetText( netName ); // set text after applying settings to avoid double-escaping
1253 netlabels.insert( { dangler.ID, label } );
1254
1255 m_sheetMap.at( dangler.LayerID )->GetScreen()->Append( label );
1256 }
1257
1258 for( NET_SCH::CONNECTION_SCH conn : net.Connections )
1259 {
1260 if( conn.LayerID == wxT( "NO_SHEET" ) )
1261 continue; // No point loading virtual connections. KiCad handles that internally
1262
1263 POINT start = getLocationOfNetElement( net, conn.StartNode );
1264 POINT end = getLocationOfNetElement( net, conn.EndNode );
1265
1266 if( start.x == UNDEFINED_VALUE || end.x == UNDEFINED_VALUE )
1267 continue;
1268
1269 // Connections in CADSTAR are always implied between symbols even if the route
1270 // doesn't start and end exactly at the connection points
1271 if( conn.Path.size() < 1 || conn.Path.front().End != start )
1272 conn.Path.insert( conn.Path.begin(), VERTEX( VERTEX_TYPE::VT_POINT, start ) );
1273
1274 if( conn.Path.size() < 2 || conn.Path.back().End != end )
1275 conn.Path.push_back( VERTEX( VERTEX_TYPE::VT_POINT, end ) );
1276
1277 bool firstPt = true;
1278 bool secondPt = false;
1279 VECTOR2I last;
1280 SCH_LINE* wire = nullptr;
1281
1282 SHAPE_LINE_CHAIN wireChain; // Create a temp. line chain representing the connection
1283
1284 auto cadstarToKicadPoint = [this]( const VECTOR2I& aPoint ) -> VECTOR2I
1285 {
1286 return getKiCadPoint( aPoint );
1287 };
1288
1289 for( const VERTEX& vertex : conn.Path )
1290 vertex.AppendToChain( &wireChain, cadstarToKicadPoint, ARC_ACCURACY );
1291
1292 // AUTO-FIX SHEET PINS
1293 //--------------------
1294 // KiCad constrains the sheet pin on the edge of the sheet object whereas in
1295 // CADSTAR it can be anywhere. Let's find the intersection of the wires with the sheet
1296 // and place the hierarchical
1297 std::vector<NETELEMENT_ID> nodes;
1298 nodes.push_back( conn.StartNode );
1299 nodes.push_back( conn.EndNode );
1300
1301 for( const NETELEMENT_ID& node : nodes )
1302 {
1303 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( node );
1304
1305 if( sheetPin )
1306 {
1307 if( sheetPin->Type() == SCH_SHEET_PIN_T
1308 && SCH_SHEET::ClassOf( sheetPin->GetParent() ) )
1309 {
1310 SCH_SHEET* parentSheet = static_cast<SCH_SHEET*>( sheetPin->GetParent() );
1311 VECTOR2I sheetSize = parentSheet->GetSize();
1312 VECTOR2I sheetPosition = parentSheet->GetPosition();
1313
1314 int leftSide = sheetPosition.x;
1315 int rightSide = sheetPosition.x + sheetSize.x;
1316 int topSide = sheetPosition.y;
1317 int botSide = sheetPosition.y + sheetSize.y;
1318
1319 SHAPE_LINE_CHAIN sheetEdge;
1320
1321 sheetEdge.Append( leftSide, topSide );
1322 sheetEdge.Append( rightSide, topSide );
1323 sheetEdge.Append( rightSide, botSide );
1324 sheetEdge.Append( leftSide, botSide );
1325 sheetEdge.Append( leftSide, topSide );
1326
1327 SHAPE_LINE_CHAIN::INTERSECTIONS wireToSheetIntersects;
1328
1329 if( !wireChain.Intersect( sheetEdge, wireToSheetIntersects ) )
1330 {
1331 // The block terminal is outside the block shape in the original
1332 // CADSTAR design. Since KiCad's Sheet Pin will already be constrained
1333 // on the edge, we will simply join to it with a straight line.
1334 if( node == conn.StartNode )
1335 wireChain = wireChain.Reverse();
1336
1337 wireChain.Append( sheetPin->GetPosition() );
1338
1339 if( node == conn.StartNode )
1340 wireChain = wireChain.Reverse();
1341 }
1342 else
1343 {
1344 // The block terminal is either inside or on the shape edge. Lets use
1345 // the first intersection point.
1346 VECTOR2I intsctPt = wireToSheetIntersects.at( 0 ).p;
1347 int intsctIndx = wireChain.FindSegment( intsctPt );
1348 wxASSERT_MSG( intsctIndx != -1, "Can't find intersecting segment" );
1349
1350 if( node == conn.StartNode )
1351 wireChain.Replace( 0, intsctIndx, intsctPt );
1352 else
1353 wireChain.Replace( intsctIndx + 1, /*end index*/ -1, intsctPt );
1354
1355 sheetPin->SetPosition( intsctPt );
1356 }
1357 }
1358 }
1359 }
1360
1361 auto fixNetLabelsAndSheetPins =
1362 [&]( const EDA_ANGLE& aWireAngle, NETELEMENT_ID& aNetEleID )
1363 {
1364 SPIN_STYLE spin = getSpinStyle( aWireAngle );
1365
1366 if( netlabels.find( aNetEleID ) != netlabels.end() )
1367 netlabels.at( aNetEleID )->SetSpinStyle( spin.MirrorY() );
1368
1369 SCH_HIERLABEL* sheetPin = getHierarchicalLabel( aNetEleID );
1370
1371 if( sheetPin )
1372 sheetPin->SetSpinStyle( spin.MirrorX() );
1373 };
1374
1375 // Now we can load the wires and fix the label orientations
1376 for( const VECTOR2I& pt : wireChain.CPoints() )
1377 {
1378 if( firstPt )
1379 {
1380 last = pt;
1381 firstPt = false;
1382 secondPt = true;
1383 continue;
1384 }
1385
1386 if( secondPt )
1387 {
1388 secondPt = false;
1389
1390 EDA_ANGLE wireAngle( last - pt );
1391 fixNetLabelsAndSheetPins( wireAngle, conn.StartNode );
1392 }
1393
1394 wire = new SCH_LINE();
1395
1396 wire->SetStartPoint( last );
1397 wire->SetEndPoint( pt );
1398 wire->SetLayer( LAYER_WIRE );
1399
1400 if( !conn.ConnectionLineCode.IsEmpty() )
1401 wire->SetLineWidth( getLineThickness( conn.ConnectionLineCode ) );
1402
1403 last = pt;
1404
1405 m_sheetMap.at( conn.LayerID )->GetScreen()->Append( wire );
1406 }
1407
1408 //Fix labels on the end wire
1409 if( wire )
1410 {
1411 EDA_ANGLE wireAngle( wire->GetEndPoint() - wire->GetStartPoint() );
1412 fixNetLabelsAndSheetPins( wireAngle, conn.EndNode );
1413 }
1414 }
1415
1416 for( std::pair<NETELEMENT_ID, NET_SCH::JUNCTION_SCH> juncPair : net.Junctions )
1417 {
1418 NET_SCH::JUNCTION_SCH junc = juncPair.second;
1419
1420 SCH_JUNCTION* kiJunc = new SCH_JUNCTION();
1421
1422 kiJunc->SetPosition( getKiCadPoint( junc.Location ) );
1423 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( kiJunc );
1424
1425 if( junc.HasNetLabel )
1426 {
1427 // In CADSTAR the label can be placed anywhere, but in KiCad it has to be placed
1428 // in the same location as the junction for it to be connected to it.
1429 SCH_LABEL* label = new SCH_LABEL();
1430 label->SetText( netName );
1431 label->SetPosition( getKiCadPoint( junc.Location ) );
1432 label->SetVisible( true );
1433
1434 EDA_ANGLE labelAngle = getAngle( junc.NetLabel.OrientAngle );
1435 SPIN_STYLE spin = getSpinStyle( labelAngle );
1436
1437 label->SetSpinStyle( spin );
1438
1439 m_sheetMap.at( junc.LayerID )->GetScreen()->Append( label );
1440 }
1441 }
1442 }
1443}
1444
1445
1447{
1448 for( std::pair<FIGURE_ID, FIGURE> figPair : Schematic.Figures )
1449 {
1450 FIGURE fig = figPair.second;
1451
1452 loadFigure( fig, fig.LayerID, LAYER_NOTES );
1453 }
1454}
1455
1456
1458{
1459 for( std::pair<TEXT_ID, TEXT> textPair : Schematic.Texts )
1460 {
1461 TEXT txt = textPair.second;
1462
1463 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1464 loadItemOntoKiCadSheet( txt.LayerID, kiTxt );
1465 }
1466}
1467
1468
1470{
1471 for( std::pair<DOCUMENTATION_SYMBOL_ID, DOCUMENTATION_SYMBOL> docSymPair :
1472 Schematic.DocumentationSymbols )
1473 {
1474 DOCUMENTATION_SYMBOL docSym = docSymPair.second;
1475
1476 if( Library.SymbolDefinitions.find( docSym.SymdefID ) == Library.SymbolDefinitions.end() )
1477 {
1478 m_reporter->Report( wxString::Format( _( "Documentation Symbol '%s' refers to symbol "
1479 "definition ID '%s' which does not exist in "
1480 "the library. The symbol was not loaded." ),
1481 docSym.ID,
1482 docSym.SymdefID ),
1484 continue;
1485 }
1486
1487 SYMDEF_SCM docSymDef = Library.SymbolDefinitions.at( docSym.SymdefID );
1488 VECTOR2I moveVector = getKiCadPoint( docSym.Origin ) - getKiCadPoint( docSymDef.Origin );
1489 EDA_ANGLE rotationAngle = getAngle( docSym.OrientAngle );
1490 double scalingFactor = (double) docSym.ScaleRatioNumerator
1491 / (double) docSym.ScaleRatioDenominator;
1492 VECTOR2I centreOfTransform = getKiCadPoint( docSymDef.Origin );
1493 bool mirrorInvert = docSym.Mirror;
1494
1495 for( std::pair<FIGURE_ID, FIGURE> figPair : docSymDef.Figures )
1496 {
1497 FIGURE fig = figPair.second;
1498
1499 loadFigure( fig, docSym.LayerID, LAYER_NOTES, moveVector, rotationAngle, scalingFactor,
1500 centreOfTransform, mirrorInvert );
1501 }
1502
1503 for( std::pair<TEXT_ID, TEXT> textPair : docSymDef.Texts )
1504 {
1505 TEXT txt = textPair.second;
1506
1507 txt.Mirror = ( txt.Mirror ) ? !mirrorInvert : mirrorInvert;
1508 txt.OrientAngle = docSym.OrientAngle - txt.OrientAngle;
1509
1510 SCH_TEXT* kiTxt = getKiCadSchText( txt );
1511
1512 VECTOR2I newPosition = applyTransform( kiTxt->GetPosition(), moveVector, rotationAngle,
1513 scalingFactor, centreOfTransform, mirrorInvert );
1514
1515 int newTxtWidth = KiROUND( kiTxt->GetTextWidth() * scalingFactor );
1516 int newTxtHeight = KiROUND( kiTxt->GetTextHeight() * scalingFactor );
1517 int newTxtThickness = KiROUND( kiTxt->GetTextThickness() * scalingFactor );
1518
1519 kiTxt->SetPosition( newPosition );
1520 kiTxt->SetTextWidth( newTxtWidth );
1521 kiTxt->SetTextHeight( newTxtHeight );
1522 kiTxt->SetTextThickness( newTxtThickness );
1523
1524 loadItemOntoKiCadSheet( docSym.LayerID, kiTxt );
1525 }
1526 }
1527}
1528
1529
1531{
1532 auto findAndReplaceTextField =
1533 [&]( TEXT_FIELD_NAME aField, wxString aValue )
1534 {
1535 if( m_context.TextFieldToValuesMap.find( aField ) != m_context.TextFieldToValuesMap.end() )
1536 {
1537 if( m_context.TextFieldToValuesMap.at( aField ) != aValue )
1538 {
1539 m_context.TextFieldToValuesMap.at( aField ) = aValue;
1540 m_context.InconsistentTextFields.insert( aField );
1541 return false;
1542 }
1543 }
1544 else
1545 {
1546 m_context.TextFieldToValuesMap.insert( { aField, aValue } );
1547 }
1548
1549 return true;
1550 };
1551
1552 PROJECT* pj = &m_schematic->Project();
1553
1554 if( pj )
1555 {
1556 std::map<wxString, wxString>& txtVars = pj->GetTextVars();
1557
1558 // Most of the design text fields can be derived from other elements
1559 if( Schematic.VariantHierarchy.Variants.size() > 0 )
1560 {
1561 VARIANT loadedVar = Schematic.VariantHierarchy.Variants.begin()->second;
1562
1563 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_NAME, loadedVar.Name );
1564 findAndReplaceTextField( TEXT_FIELD_NAME::VARIANT_DESCRIPTION, loadedVar.Description );
1565 }
1566
1567 findAndReplaceTextField( TEXT_FIELD_NAME::DESIGN_TITLE, Header.JobTitle );
1568
1569 for( std::pair<TEXT_FIELD_NAME, wxString> txtvalue : m_context.TextFieldToValuesMap )
1570 {
1571 wxString varName = CADSTAR_TO_KICAD_FIELDS.at( txtvalue.first );
1572 wxString varValue = txtvalue.second;
1573
1574 txtVars.insert( { varName, varValue } );
1575 }
1576
1577 for( std::pair<wxString, wxString> txtvalue : m_context.FilenamesToTextMap )
1578 {
1579 wxString varName = txtvalue.first;
1580 wxString varValue = txtvalue.second;
1581
1582 txtVars.insert( { varName, varValue } );
1583 }
1584 }
1585 else
1586 {
1587 m_reporter->Report( _( "Text Variables could not be set as there is no project attached." ),
1589 }
1590}
1591
1592
1593SCH_FIELD*
1595 std::unique_ptr<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.get(), 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 );
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 );
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 );
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 //todo: need to use unique_ptr more. For now just create it here and release at end of function
1840 std::unique_ptr<LIB_SYMBOL> tempSymbol( aSymbol );
1841
1842 // Update the pin numbers to match those defined in the Cadstar part
1843 TERMINAL_TO_PINNUM_MAP pinNumMap;
1844
1845 for( auto&& [storedPinNum, termID] : m_symDefTerminalsMap[aSymdefID] )
1846 {
1847 PART::DEFINITION::PIN csPin = getPartDefinitionPin( aCadstarPart, aGateID, termID );
1848 std::vector<SCH_PIN*> pins = kiSymDef->GetPinsByNumber( storedPinNum );
1849
1850 wxString pinName = HandleTextOverbar( csPin.Label );
1851 wxString pinNum = HandleTextOverbar( csPin.Name );
1852
1853 if( pinNum.IsEmpty() )
1854 {
1855 if( !csPin.Identifier.IsEmpty() )
1856 pinNum = csPin.Identifier;
1857 else if( csPin.ID == UNDEFINED_VALUE )
1858 pinNum = wxString::Format( "%ld", termID );
1859 else
1860 pinNum = wxString::Format( "%ld", csPin.ID );
1861 }
1862
1863 for( SCH_PIN* pin : pins )
1864 {
1865 pin->SetType( getKiCadPinType( csPin.Type ) );
1866 pin->SetNumber( pinNum );
1867 pin->SetName( pinName );
1868 }
1869
1870 pinNumMap.insert( { termID, pinNum } );
1871 }
1872
1873 m_pinNumsMap.insert( { aCadstarPart.ID + aGateID, pinNumMap } );
1874
1875 // COPY ITEMS
1876 int gateNumber = getKiCadUnitNumberFromGate( aGateID );
1877 copySymbolItems( kiSymDef, tempSymbol, gateNumber );
1878
1879 // Hide the value field for now (it might get unhidden if an attribute exists in the cadstar
1880 // design with the text "Value"
1881 tempSymbol->GetValueField().SetVisible( false );
1882
1883
1884 if( SCH_FIELD* partNameField = tempSymbol->GetField( PartNameFieldName ) )
1885 partNameField->SetText( EscapeFieldText( aCadstarPart.Name ) );
1886
1887 const POINT& symDefOrigin = Library.SymbolDefinitions.at( aSymdefID ).Origin;
1888 wxString footprintRefName = wxEmptyString;
1889 wxString footprintAlternateName = wxEmptyString;
1890
1891 auto loadLibraryField = [&]( const ATTRIBUTE_VALUE& aAttributeVal )
1892 {
1893 wxString attrName = getAttributeName( aAttributeVal.AttributeID );
1894
1895 // Remove invalid field characters
1896 wxString attributeValue = aAttributeVal.Value;
1897 attributeValue.Replace( wxT( "\n" ), wxT( "\\n" ) );
1898 attributeValue.Replace( wxT( "\r" ), wxT( "\\r" ) );
1899 attributeValue.Replace( wxT( "\t" ), wxT( "\\t" ) );
1900
1901 //TODO: Handle "links": In cadstar a field can be a "link" if its name starts
1902 // with the characters "Link ". Need to figure out how to convert them to
1903 // equivalent in KiCad.
1904
1905 if( attrName == wxT( "(PartDefinitionNameStem)" ) )
1906 {
1907 //Space not allowed in Reference field
1908 attributeValue.Replace( wxT( " " ), "_" );
1909 tempSymbol->GetReferenceField().SetText( attributeValue );
1910 return;
1911 }
1912 else if( attrName == wxT( "(PartDescription)" ) )
1913 {
1914 tempSymbol->SetDescription( attributeValue );
1915 return;
1916 }
1917 else if( attrName == wxT( "(PartDefinitionReferenceName)" ) )
1918 {
1919 footprintRefName = attributeValue;
1920 return;
1921 }
1922 else if( attrName == wxT( "(PartDefinitionAlternateName)" ) )
1923 {
1924 footprintAlternateName = attributeValue;
1925 return;
1926 }
1927
1928 bool attrIsNew = tempSymbol->GetField( attrName ) == nullptr;
1929 SCH_FIELD* attrField = addNewFieldToSymbol( attrName, tempSymbol );
1930
1931 wxASSERT( attrField->GetName() == attrName );
1932 attrField->SetText( aAttributeVal.Value );
1933 attrField->SetUnit( gateNumber );
1934
1935 const ATTRIBUTE_ID& attrid = aAttributeVal.AttributeID;
1936 attrField->SetVisible( isAttributeVisible( attrid ) );
1937
1938 if( aAttributeVal.HasLocation )
1939 {
1940 // Check if the part itself defined a location for the field
1941 applyToLibraryFieldAttribute( aAttributeVal.AttributeLocation, symDefOrigin,
1942 attrField );
1943 }
1944 else if( attrIsNew )
1945 {
1946 attrField->SetVisible( false );
1947 applyTextSettings( attrField, wxT( "TC1" ), ALIGNMENT::NO_ALIGNMENT,
1948 JUSTIFICATION::LEFT, false, true );
1949 }
1950 };
1951
1952 // Load all attributes in the Part Definition
1953 for( auto& [attrId, attrVal] : aCadstarPart.Definition.AttributeValues )
1954 loadLibraryField( attrVal );
1955
1956 // Load all attributes in the Part itself.
1957 for( auto& [attrId, attrVal] : aCadstarPart.AttributeValues )
1958 loadLibraryField( attrVal );
1959
1960 setFootprintOnSymbol( tempSymbol, footprintRefName, footprintAlternateName );
1961
1962 if( aCadstarPart.Definition.HidePinNames )
1963 {
1964 tempSymbol->SetShowPinNames( false );
1965 tempSymbol->SetShowPinNumbers( false );
1966 }
1967
1968 // Update aSymbol just to keep lint happy.
1969 aSymbol = tempSymbol.release();
1970}
1971
1972
1973void CADSTAR_SCH_ARCHIVE_LOADER::setFootprintOnSymbol( std::unique_ptr<LIB_SYMBOL>& aKiCadSymbol,
1974 const wxString& aFootprintName,
1975 const wxString& aFootprintAlternate )
1976{
1977 wxString fpNameInLibrary = generateLibName( aFootprintName, aFootprintAlternate );
1978
1979 if( !fpNameInLibrary.IsEmpty() )
1980 {
1981 wxArrayString fpFilters;
1982 fpFilters.Add( aFootprintName ); // In cadstar one footprint has several "alternates"
1983
1984 if( !aFootprintAlternate.IsEmpty() )
1985 fpFilters.Add( fpNameInLibrary );
1986
1987 aKiCadSymbol->SetFPFilters( fpFilters );
1988
1989 LIB_ID libID( m_footprintLibName, fpNameInLibrary );
1990 aKiCadSymbol->GetFootprintField().SetText( libID.Format() );
1991 }
1992}
1993
1994
1995void CADSTAR_SCH_ARCHIVE_LOADER::loadLibrarySymbolShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
1996 const VECTOR2I& aSymbolOrigin,
1997 LIB_SYMBOL* aSymbol,
1998 int aGateNumber,
1999 int aLineThickness )
2000{
2001 const VERTEX* prev = &aCadstarVertices.at( 0 );
2002 const VERTEX* cur;
2003
2004 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT, "First vertex should always be a point." );
2005
2006 for( size_t i = 1; i < aCadstarVertices.size(); i++ )
2007 {
2008 cur = &aCadstarVertices.at( i );
2009
2010 SCH_SHAPE* shape = nullptr;
2011 bool cw = false;
2012 VECTOR2I startPoint = getKiCadLibraryPoint( prev->End, aSymbolOrigin );
2013 VECTOR2I endPoint = getKiCadLibraryPoint( cur->End, aSymbolOrigin );
2014 VECTOR2I centerPoint;
2015
2018 {
2019 centerPoint = ( startPoint + endPoint ) / 2;
2020 }
2021 else
2022 {
2023 centerPoint = getKiCadLibraryPoint( cur->Center, aSymbolOrigin );
2024 }
2025
2026
2027 switch( cur->Type )
2028 {
2030 shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
2031 shape->AddPoint( startPoint );
2032 shape->AddPoint( endPoint );
2033 break;
2034
2037 cw = true;
2039
2042 shape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
2043
2044 shape->SetPosition( centerPoint );
2045
2046 if( cw )
2047 {
2048 shape->SetStart( endPoint );
2049 shape->SetEnd( startPoint );
2050 }
2051 else
2052 {
2053 shape->SetStart( startPoint );
2054 shape->SetEnd( endPoint );
2055 }
2056
2057 break;
2058 }
2059
2060 shape->SetUnit( aGateNumber );
2061 shape->SetStroke( STROKE_PARAMS( aLineThickness, LINE_STYLE::SOLID ) );
2062 aSymbol->AddDrawItem( shape, false );
2063
2064 prev = cur;
2065 }
2066
2067 aSymbol->GetDrawItems().sort();
2068}
2069
2070
2072 const VECTOR2I& aSymbolOrigin,
2073 SCH_FIELD* aKiCadField )
2074{
2075 aKiCadField->SetTextPos( getKiCadLibraryPoint( aCadstarAttrLoc.Position, aSymbolOrigin ) );
2076
2077 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, aCadstarAttrLoc.Alignment,
2078 aCadstarAttrLoc.Justification, aCadstarAttrLoc.OrientAngle,
2079 aCadstarAttrLoc.Mirror );
2080}
2081
2082
2084 const LIB_SYMBOL& aKiCadPart,
2085 EDA_ANGLE& aComponentOrientation )
2086{
2087 wxString libName = CreateLibName( m_footprintLibName, m_rootSheet );
2088
2089 LIB_ID libId;
2090 libId.SetLibItemName( aKiCadPart.GetName() );
2091 libId.SetLibNickname( libName );
2092
2093 int unit = getKiCadUnitNumberFromGate( aCadstarSymbol.GateID );
2094
2095 SCH_SHEET_PATH sheetpath;
2096 SCH_SHEET* kiSheet = m_sheetMap.at( aCadstarSymbol.LayerID );
2097 m_rootSheet->LocatePathOfScreen( kiSheet->GetScreen(), &sheetpath );
2098
2099 SCH_SYMBOL* symbol = new SCH_SYMBOL( aKiCadPart, libId, &sheetpath, unit );
2100
2101 if( aCadstarSymbol.IsComponent )
2102 symbol->SetRef( &sheetpath, aCadstarSymbol.ComponentRef.Designator );
2103
2104 symbol->SetPosition( getKiCadPoint( aCadstarSymbol.Origin ) );
2105
2106 EDA_ANGLE compAngle = getAngle( aCadstarSymbol.OrientAngle );
2107 int compOrientation = 0;
2108
2109 if( aCadstarSymbol.Mirror )
2110 {
2111 compAngle = -compAngle;
2112 compOrientation += SYMBOL_ORIENTATION_T::SYM_MIRROR_Y;
2113 }
2114
2115 compOrientation += getComponentOrientation( compAngle, aComponentOrientation );
2116 EDA_ANGLE test1( compAngle );
2117 EDA_ANGLE test2( aComponentOrientation );
2118
2119 if( test1.Normalize180() != test2.Normalize180() )
2120 {
2121 m_reporter->Report( wxString::Format( _( "Symbol '%s' is rotated by an angle of %.1f " //format:allow
2122 "degrees in the original CADSTAR design but "
2123 "KiCad only supports rotation angles multiples "
2124 "of 90 degrees. The connecting wires will need "
2125 "manual fixing." ),
2126 aCadstarSymbol.ComponentRef.Designator,
2127 compAngle.AsDegrees() ),
2129 }
2130
2131 symbol->SetOrientation( compOrientation );
2132
2133 if( m_sheetMap.find( aCadstarSymbol.LayerID ) == m_sheetMap.end() )
2134 {
2135 m_reporter->Report( wxString::Format( _( "Symbol '%s' references sheet ID '%s' which does "
2136 "not exist in the design. The symbol was not "
2137 "loaded." ),
2138 aCadstarSymbol.ComponentRef.Designator,
2139 aCadstarSymbol.LayerID ),
2141
2142 delete symbol;
2143 return nullptr;
2144 }
2145
2146 wxString gate = ( aCadstarSymbol.GateID.IsEmpty() ) ? wxString( wxT( "A" ) ) : aCadstarSymbol.GateID;
2147 wxString partGateIndex = aCadstarSymbol.PartRef.RefID + gate;
2148
2149 //Handle pin swaps
2150 if( m_pinNumsMap.find( partGateIndex ) != m_pinNumsMap.end() )
2151 {
2152 TERMINAL_TO_PINNUM_MAP termNumMap = m_pinNumsMap.at( partGateIndex );
2153
2154 std::map<wxString, std::vector<SCH_PIN*>> pinNumToLibPinsMap;
2155
2156 for( auto& term : termNumMap )
2157 {
2158 wxString pinNum = term.second;
2159 std::vector<SCH_PIN*> pins =
2160 symbol->GetLibSymbolRef()->GetPinsByNumber( term.second );
2161 pinNumToLibPinsMap.insert( { pinNum, pins } );
2162 }
2163
2164 auto replacePinNumber =
2165 [&]( wxString aOldPinNum, wxString aNewPinNum )
2166 {
2167 if( aOldPinNum == aNewPinNum )
2168 return;
2169
2170 for( SCH_PIN* libpin : pinNumToLibPinsMap.at( aOldPinNum ) )
2171 libpin->SetNumber( HandleTextOverbar( aNewPinNum ) );
2172 };
2173
2174 //Older versions of Cadstar used pin numbers
2175 for( auto& pinPair : aCadstarSymbol.PinNumbers )
2176 {
2177 SYMBOL::PIN_NUM pin = pinPair.second;
2178
2179 replacePinNumber( termNumMap.at( pin.TerminalID ),
2180 wxString::Format( "%ld", pin.PinNum ) );
2181 }
2182
2183 //Newer versions of Cadstar use pin names
2184 for( auto& pinPair : aCadstarSymbol.PinNames )
2185 {
2186 SYMPINNAME_LABEL pin = pinPair.second;
2187 replacePinNumber( termNumMap.at( pin.TerminalID ), pin.NameOrLabel );
2188 }
2189
2190 symbol->UpdatePins();
2191 }
2192
2193 kiSheet->GetScreen()->Append( symbol );
2194
2195 return symbol;
2196}
2197
2198
2200 const EDA_ANGLE& aComponentOrientation,
2201 bool aIsMirrored,
2202 SCH_FIELD* aKiCadField )
2203{
2204 aKiCadField->SetPosition( getKiCadPoint( aCadstarAttrLoc.Position ) );
2205 aKiCadField->SetVisible( true );
2206
2207 ALIGNMENT alignment = aCadstarAttrLoc.Alignment;
2208 EDA_ANGLE textAngle = getAngle( aCadstarAttrLoc.OrientAngle );
2209
2210 if( aIsMirrored )
2211 {
2212 // We need to change the aligment when the symbol is mirrored based on the text orientation
2213 // To ensure the anchor point is the same in KiCad.
2214
2215 int textIsVertical = KiROUND( textAngle.AsDegrees() / 90.0 ) % 2;
2216
2217 if( textIsVertical )
2218 alignment = rotate180( alignment );
2219
2220 alignment = mirrorX( alignment );
2221 }
2222
2223 applyTextSettings( aKiCadField, aCadstarAttrLoc.TextCodeID, alignment,
2224 aCadstarAttrLoc.Justification,
2225 getCadstarAngle( textAngle - aComponentOrientation ),
2226 aCadstarAttrLoc.Mirror );
2227}
2228
2229
2231 EDA_ANGLE& aReturnedOrientation )
2232{
2233 int compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2234
2235 EDA_ANGLE oDeg = aOrientAngle;
2236 oDeg.Normalize180();
2237
2238 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2239 {
2240 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_0;
2241 aReturnedOrientation = ANGLE_0;
2242 }
2243 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2244 {
2245 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_90;
2246 aReturnedOrientation = ANGLE_90;
2247 }
2248 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2249 {
2250 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_180;
2251 aReturnedOrientation = ANGLE_180;
2252 }
2253 else
2254 {
2255 compOrientation = SYMBOL_ORIENTATION_T::SYM_ORIENT_270;
2256 aReturnedOrientation = ANGLE_270;
2257 }
2258
2259 return compOrientation;
2260}
2261
2262
2265 const NETELEMENT_ID& aNetElementID )
2266{
2267 // clang-format off
2268 auto logUnknownNetElementError =
2269 [&]()
2270 {
2271 m_reporter->Report( wxString::Format( _( "Net %s references unknown net element %s. "
2272 "The net was not properly loaded and may "
2273 "require manual fixing." ),
2274 getNetName( aNet ),
2275 aNetElementID ),
2277
2278 return POINT();
2279 };
2280 // clang-format on
2281
2282 if( aNetElementID.Contains( "J" ) ) // Junction
2283 {
2284 if( aNet.Junctions.find( aNetElementID ) == aNet.Junctions.end() )
2285 return logUnknownNetElementError();
2286
2287 return aNet.Junctions.at( aNetElementID ).Location;
2288 }
2289 else if( aNetElementID.Contains( "P" ) ) // Terminal/Pin of a symbol
2290 {
2291 if( aNet.Terminals.find( aNetElementID ) == aNet.Terminals.end() )
2292 return logUnknownNetElementError();
2293
2294 SYMBOL_ID symid = aNet.Terminals.at( aNetElementID ).SymbolID;
2295 TERMINAL_ID termid = aNet.Terminals.at( aNetElementID ).TerminalID;
2296
2297 if( Schematic.Symbols.find( symid ) == Schematic.Symbols.end() )
2298 return logUnknownNetElementError();
2299
2300 SYMBOL sym = Schematic.Symbols.at( symid );
2301 SYMDEF_ID symdefid = sym.SymdefID;
2302 VECTOR2I symbolOrigin = sym.Origin;
2303
2304 if( Library.SymbolDefinitions.find( symdefid ) == Library.SymbolDefinitions.end() )
2305 return logUnknownNetElementError();
2306
2307 VECTOR2I libpinPosition =
2308 Library.SymbolDefinitions.at( symdefid ).Terminals.at( termid ).Position;
2309 VECTOR2I libOrigin = Library.SymbolDefinitions.at( symdefid ).Origin;
2310
2311 VECTOR2I pinOffset = libpinPosition - libOrigin;
2312 pinOffset.x = ( pinOffset.x * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2313 pinOffset.y = ( pinOffset.y * sym.ScaleRatioNumerator ) / sym.ScaleRatioDenominator;
2314
2315 VECTOR2I pinPosition = symbolOrigin + pinOffset;
2316 EDA_ANGLE compAngle = getAngle( sym.OrientAngle );
2317
2318 if( sym.Mirror )
2319 pinPosition.x = ( 2 * symbolOrigin.x ) - pinPosition.x;
2320
2321 EDA_ANGLE adjustedOrientation;
2322 getComponentOrientation( compAngle, adjustedOrientation );
2323
2324 RotatePoint( pinPosition, symbolOrigin, -adjustedOrientation );
2325
2326 POINT retval;
2327 retval.x = pinPosition.x;
2328 retval.y = pinPosition.y;
2329
2330 return retval;
2331 }
2332 else if( aNetElementID.Contains( "BT" ) ) // Bus Terminal
2333 {
2334 if( aNet.BusTerminals.find( aNetElementID ) == aNet.BusTerminals.end() )
2335 return logUnknownNetElementError();
2336
2337 return aNet.BusTerminals.at( aNetElementID ).SecondPoint;
2338 }
2339 else if( aNetElementID.Contains( "BLKT" ) ) // Block Terminal (sheet hierarchy connection)
2340 {
2341 if( aNet.BlockTerminals.find( aNetElementID ) == aNet.BlockTerminals.end() )
2342 return logUnknownNetElementError();
2343
2344 BLOCK_ID blockid = aNet.BlockTerminals.at( aNetElementID ).BlockID;
2345 TERMINAL_ID termid = aNet.BlockTerminals.at( aNetElementID ).TerminalID;
2346
2347 if( Schematic.Blocks.find( blockid ) == Schematic.Blocks.end() )
2348 return logUnknownNetElementError();
2349
2350 return Schematic.Blocks.at( blockid ).Terminals.at( termid ).Position;
2351 }
2352 else if( aNetElementID.Contains( "D" ) ) // Dangler
2353 {
2354 if( aNet.Danglers.find( aNetElementID ) == aNet.Danglers.end() )
2355 return logUnknownNetElementError();
2356
2357 return aNet.Danglers.at( aNetElementID ).Position;
2358 }
2359 else
2360 {
2361 return logUnknownNetElementError();
2362 }
2363}
2364
2365
2367{
2368 wxString netname = aNet.Name;
2369
2370 if( netname.IsEmpty() )
2371 netname = wxString::Format( "$%ld", aNet.SignalNum );
2372
2373 return netname;
2374}
2375
2376
2377void CADSTAR_SCH_ARCHIVE_LOADER::loadShapeVertices( const std::vector<VERTEX>& aCadstarVertices,
2378 LINECODE_ID aCadstarLineCodeID,
2379 LAYER_ID aCadstarSheetID,
2380 SCH_LAYER_ID aKiCadSchLayerID,
2381 const VECTOR2I& aMoveVector,
2382 const EDA_ANGLE& aRotation,
2383 const double& aScalingFactor,
2384 const VECTOR2I& aTransformCentre,
2385 const bool& aMirrorInvert )
2386{
2387 int lineWidth = KiROUND( getLineThickness( aCadstarLineCodeID ) * aScalingFactor );
2388 LINE_STYLE lineStyle = getLineStyle( aCadstarLineCodeID );
2389
2390 const VERTEX* prev = &aCadstarVertices.at( 0 );
2391 const VERTEX* cur;
2392
2393 wxASSERT_MSG( prev->Type == VERTEX_TYPE::VT_POINT,
2394 "First vertex should always be a point vertex" );
2395
2396 auto pointTransform =
2397 [&]( const VECTOR2I& aV )
2398 {
2399 return applyTransform( getKiCadPoint( aV ), aMoveVector, aRotation,
2400 aScalingFactor, aTransformCentre, aMirrorInvert );
2401 };
2402
2403 for( size_t ii = 1; ii < aCadstarVertices.size(); ii++ )
2404 {
2405 cur = &aCadstarVertices.at( ii );
2406
2407 VECTOR2I transformedStartPoint = pointTransform( prev->End );
2408 VECTOR2I transformedEndPoint = pointTransform( cur->End );
2409
2410 switch( cur->Type )
2411 {
2416 {
2417 SHAPE_ARC tempArc = cur->BuildArc( transformedStartPoint, pointTransform );
2418
2419 SCH_SHAPE* arcShape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_NOTES, lineWidth );
2420 arcShape->SetArcGeometry( tempArc.GetP0(), tempArc.GetArcMid(), tempArc.GetP1() );
2421
2422 loadItemOntoKiCadSheet( aCadstarSheetID, arcShape );
2423 break;
2424 }
2425
2427 {
2428 SCH_LINE* segment = new SCH_LINE();
2429
2430 segment->SetLayer( aKiCadSchLayerID );
2431 segment->SetLineWidth( lineWidth );
2432 segment->SetLineStyle( lineStyle );
2433
2434 segment->SetStartPoint( transformedStartPoint );
2435 segment->SetEndPoint( transformedEndPoint );
2436
2437 loadItemOntoKiCadSheet( aCadstarSheetID, segment );
2438 break;
2439 }
2440
2441 default:
2442 wxFAIL_MSG( "Unknown CADSTAR Vertex type" );
2443 }
2444
2445 prev = cur;
2446 }
2447}
2448
2449
2451 const LAYER_ID& aCadstarSheetIDOverride,
2452 SCH_LAYER_ID aKiCadSchLayerID,
2453 const VECTOR2I& aMoveVector,
2454 const EDA_ANGLE& aRotation,
2455 const double& aScalingFactor,
2456 const VECTOR2I& aTransformCentre,
2457 const bool& aMirrorInvert )
2458{
2459 loadShapeVertices( aCadstarFigure.Shape.Vertices, aCadstarFigure.LineCodeID,
2460 aCadstarSheetIDOverride, aKiCadSchLayerID, aMoveVector, aRotation,
2461 aScalingFactor, aTransformCentre, aMirrorInvert );
2462
2463 for( const CUTOUT& cutout : aCadstarFigure.Shape.Cutouts )
2464 {
2465 loadShapeVertices( cutout.Vertices, aCadstarFigure.LineCodeID, aCadstarSheetIDOverride,
2466 aKiCadSchLayerID, aMoveVector, aRotation, aScalingFactor,
2467 aTransformCentre, aMirrorInvert );
2468 }
2469}
2470
2471
2473 const VECTOR2I& aPosition,
2474 const VECTOR2I& aSheetSize,
2475 const SCH_SHEET_PATH& aParentSheet )
2476{
2477 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) == m_sheetMap.end(), ,
2478 "Sheet already loaded!" );
2479
2480 SCH_SHEET* sheet = new SCH_SHEET(
2481 /* aParent */ aParentSheet.Last(),
2482 /* aPosition */ aPosition,
2483 /* aSize */ VECTOR2I( aSheetSize ) );
2484 SCH_SCREEN* screen = new SCH_SCREEN( m_schematic );
2485 SCH_SHEET_PATH instance( aParentSheet );
2486
2487 sheet->SetScreen( screen );
2488
2489 wxString name = Sheets.SheetNames.at( aCadstarSheetID );
2490
2492
2493 int sheetNum = getSheetNumber( aCadstarSheetID );
2494 wxString loadedFilename = wxFileName( Filename ).GetName();
2495 std::string filename = wxString::Format( "%s_%02d", loadedFilename, sheetNum ).ToStdString();
2496
2497 ReplaceIllegalFileNameChars( filename );
2498 filename += wxT( "." ) + wxString( FILEEXT::KiCadSchematicFileExtension );
2499
2500 sheet->GetField( FIELD_T::SHEET_FILENAME )->SetText( filename );
2501
2502 wxFileName fn( m_schematic->Project().GetProjectPath() + filename );
2503 sheet->GetScreen()->SetFileName( fn.GetFullPath() );
2504 aParentSheet.Last()->GetScreen()->Append( sheet );
2505 instance.push_back( sheet );
2506
2507 wxString pageNumStr = wxString::Format( "%d", getSheetNumber( aCadstarSheetID ) );
2508 instance.SetPageNumber( pageNumStr );
2509
2510 sheet->AutoplaceFields( nullptr, AUTOPLACE_AUTO );
2511
2512 m_sheetMap.insert( { aCadstarSheetID, sheet } );
2513
2514 loadChildSheets( aCadstarSheetID, instance );
2515}
2516
2517
2519 const SCH_SHEET_PATH& aSheet )
2520{
2521 wxCHECK_MSG( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end(), ,
2522 "FIXME! Parent sheet should be loaded before attempting to load subsheets" );
2523
2524 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2525 {
2526 BLOCK& block = blockPair.second;
2527
2528 if( block.LayerID == aCadstarSheetID && block.Type == BLOCK::TYPE::CHILD )
2529 {
2530 if( block.AssocLayerID == wxT( "NO_LINK" ) )
2531 {
2532 if( block.Figures.size() > 0 )
2533 {
2534 m_reporter->Report( wxString::Format( _( "The block ID %s (Block name: '%s') "
2535 "is drawn on sheet '%s' but is not "
2536 "linked to another sheet in the "
2537 "design. KiCad requires all sheet "
2538 "symbols to be associated to a sheet, "
2539 "so the block was not loaded." ),
2540 block.ID, block.Name,
2541 Sheets.SheetNames.at( aCadstarSheetID ) ),
2543 }
2544
2545 continue;
2546 }
2547
2548 // In KiCad you can only draw rectangular shapes whereas in Cadstar arbitrary shapes
2549 // are allowed. We will calculate the extents of the Cadstar shape and draw a rectangle
2550
2551 std::pair<VECTOR2I, VECTOR2I> blockExtents;
2552
2553 if( block.Figures.size() > 0 )
2554 {
2555 blockExtents = getFigureExtentsKiCad( block.Figures.begin()->second );
2556 }
2557 else
2558 {
2559 THROW_IO_ERROR( wxString::Format( _( "The CADSTAR schematic might be corrupt: "
2560 "Block %s references a child sheet but has no "
2561 "Figure defined." ),
2562 block.ID ) );
2563 }
2564
2565 loadSheetAndChildSheets( block.AssocLayerID, blockExtents.first, blockExtents.second,
2566 aSheet );
2567
2568 // Hide all KiCad sheet properties (sheet name/filename is not applicable in CADSTAR)
2569 SCH_SHEET* loadedSheet = m_sheetMap.at( block.AssocLayerID );
2570 std::vector<SCH_FIELD> fields = loadedSheet->GetFields();
2571
2572 for( SCH_FIELD& field : fields )
2573 {
2574 field.SetVisible( false );
2575 }
2576
2577 if( block.HasBlockLabel )
2578 {
2579 //@todo use below code when KiCad supports multi-line fields
2580 /*
2581 // Add the block label as a separate field
2582 SCH_FIELD blockNameField( getKiCadPoint( block.BlockLabel.Position ), 2,
2583 loadedSheet, wxString( "Block name" ) );
2584 blockNameField.SetText( block.Name );
2585 blockNameField.SetVisible( true );
2586
2587 applyTextSettings( &blockNameField,
2588 block.BlockLabel.TextCodeID,
2589 block.BlockLabel.Alignment,
2590 block.BlockLabel.Justification,
2591 block.BlockLabel.OrientAngle,
2592 block.BlockLabel.Mirror );
2593
2594 fields.push_back( blockNameField );*/
2595
2596 // For now as as a text item (supports multi-line properly)
2597 SCH_TEXT* kiTxt = new SCH_TEXT();
2598
2599 kiTxt->SetParent( m_schematic );
2600 kiTxt->SetPosition( getKiCadPoint( block.BlockLabel.Position ) );
2601 kiTxt->SetText( block.Name );
2602
2605 block.BlockLabel.Mirror );
2606
2607 loadItemOntoKiCadSheet( aCadstarSheetID, kiTxt );
2608 }
2609
2610 loadedSheet->SetFields( fields );
2611 }
2612 }
2613}
2614
2615
2616std::vector<CADSTAR_SCH_ARCHIVE_LOADER::LAYER_ID> CADSTAR_SCH_ARCHIVE_LOADER::findOrphanSheets()
2617{
2618 std::vector<LAYER_ID> childSheets, orphanSheets;
2619
2620 //Find all sheets that are child of another
2621 for( std::pair<BLOCK_ID, BLOCK> blockPair : Schematic.Blocks )
2622 {
2623 BLOCK& block = blockPair.second;
2624 LAYER_ID& assocSheetID = block.AssocLayerID;
2625
2626 if( block.Type == BLOCK::TYPE::CHILD )
2627 childSheets.push_back( assocSheetID );
2628 }
2629
2630 //Add sheets that do not have a parent
2631 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2632 {
2633 if( std::find( childSheets.begin(), childSheets.end(), sheetID ) == childSheets.end() )
2634 orphanSheets.push_back( sheetID );
2635 }
2636
2637 return orphanSheets;
2638}
2639
2640
2642{
2643 int i = 1;
2644
2645 for( const LAYER_ID& sheetID : Sheets.SheetOrder )
2646 {
2647 if( sheetID == aCadstarSheetID )
2648 return i;
2649
2650 ++i;
2651 }
2652
2653 return -1;
2654}
2655
2656
2658 SCH_ITEM* aItem )
2659{
2660 wxCHECK_MSG( aItem, /*void*/, wxT( "aItem is null" ) );
2661
2662 if( aCadstarSheetID == "ALL_SHEETS" )
2663 {
2664 SCH_ITEM* duplicateItem = nullptr;
2665
2666 for( std::pair<LAYER_ID, SHEET_NAME> sheetPair : Sheets.SheetNames )
2667 {
2668 LAYER_ID sheetID = sheetPair.first;
2669 duplicateItem = aItem->Duplicate( IGNORE_PARENT_GROUP );
2670 m_sheetMap.at( sheetID )->GetScreen()->Append( aItem->Duplicate( IGNORE_PARENT_GROUP ) );
2671 }
2672
2673 //Get rid of the extra copy:
2674 delete aItem;
2675 aItem = duplicateItem;
2676 }
2677 else if( aCadstarSheetID == "NO_SHEET" )
2678 {
2679 wxFAIL_MSG( wxT( "Trying to add an item to NO_SHEET? This might be a documentation symbol." ) );
2680 }
2681 else
2682 {
2683 if( m_sheetMap.find( aCadstarSheetID ) != m_sheetMap.end() )
2684 {
2685 m_sheetMap.at( aCadstarSheetID )->GetScreen()->Append( aItem );
2686 }
2687 else
2688 {
2689 delete aItem;
2690 wxFAIL_MSG( wxT( "Unknown Sheet ID." ) );
2691 }
2692 }
2693}
2694
2695
2698 const wxString& aSymDefAlternate )
2699{
2700 if( m_SymDefNamesCache.size() != Library.SymbolDefinitions.size() )
2701 {
2702 // Re-initialise
2703 m_SymDefNamesCache.clear();
2705
2706 // Create a lower case cache to avoid searching each time
2707 for( auto& [id, symdef] : Library.SymbolDefinitions )
2708 {
2709 wxString refKey = symdef.ReferenceName.Lower();
2710 wxString altKey = symdef.Alternate.Lower();
2711
2712 m_SymDefNamesCache[{ refKey, altKey }] = id;
2713
2714 // Secondary cache to find symbols just by the Name (e.g. if the alternate
2715 // does not exist, we still want to return a symbo - the same behaviour
2716 // as CADSTAR
2717
2718 if( !m_DefaultSymDefNamesCache.count( refKey ) )
2719 {
2720 m_DefaultSymDefNamesCache.insert( { refKey, id } );
2721 }
2722 else if( altKey.IsEmpty() )
2723 {
2724 // Always use the empty alternate if it exists
2725 m_DefaultSymDefNamesCache[refKey] = id;
2726 }
2727 }
2728 }
2729
2730 wxString refKeyToFind = aSymdefName.Lower();
2731 wxString altKeyToFind = aSymDefAlternate.Lower();
2732
2733 if( m_SymDefNamesCache.count( { refKeyToFind, altKeyToFind } ) )
2734 {
2735 return m_SymDefNamesCache[{ refKeyToFind, altKeyToFind }];
2736 }
2737 else if( m_DefaultSymDefNamesCache.count( refKeyToFind ) )
2738 {
2739 return m_DefaultSymDefNamesCache[refKeyToFind];
2740 }
2741
2742 return SYMDEF_ID();
2743}
2744
2745
2747{
2748 // Use CADSTAR visibility settings to determine if an attribute is visible
2749 if( AttrColors.AttributeColors.find( aCadstarAttributeID ) != AttrColors.AttributeColors.end() )
2750 return AttrColors.AttributeColors.at( aCadstarAttributeID ).IsVisible;
2751
2752 return false; // If there is no visibility setting, assume not displayed
2753}
2754
2755
2757{
2758 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2759 != Assignments.Codedefs.LineCodes.end(),
2760 schIUScale.MilsToIU( DEFAULT_WIRE_WIDTH_MILS ) );
2761
2762 return getKiCadLength( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Width );
2763}
2764
2765
2767{
2768 wxCHECK( Assignments.Codedefs.LineCodes.find( aCadstarLineCodeID )
2769 != Assignments.Codedefs.LineCodes.end(),
2771
2772 // clang-format off
2773 switch( Assignments.Codedefs.LineCodes.at( aCadstarLineCodeID ).Style )
2774 {
2775 case LINESTYLE::DASH: return LINE_STYLE::DASH;
2777 case LINESTYLE::DASHDOTDOT: return LINE_STYLE::DASHDOT; //TODO: update in future
2778 case LINESTYLE::DOT: return LINE_STYLE::DOT;
2780 default: return LINE_STYLE::DEFAULT;
2781 }
2782 // clang-format on
2783}
2784
2785
2788{
2789 wxCHECK( Assignments.Codedefs.TextCodes.find( aCadstarTextCodeID )
2790 != Assignments.Codedefs.TextCodes.end(),
2791 TEXTCODE() );
2792
2793 return Assignments.Codedefs.TextCodes.at( aCadstarTextCodeID );
2794}
2795
2796
2798{
2799 TEXTCODE txtCode = getTextCode( aCadstarTextCodeID );
2800
2801 return KiROUND( (double) getKiCadLength( txtCode.Height ) * TXT_HEIGHT_RATIO );
2802}
2803
2804
2806{
2807 wxCHECK( Assignments.Codedefs.AttributeNames.find( aCadstarAttributeID )
2808 != Assignments.Codedefs.AttributeNames.end(),
2809 aCadstarAttributeID );
2810
2811 return Assignments.Codedefs.AttributeNames.at( aCadstarAttributeID ).Name;
2812}
2813
2814
2817{
2818 wxCHECK( Parts.PartDefinitions.find( aCadstarPartID ) != Parts.PartDefinitions.end(), PART() );
2819
2820 return Parts.PartDefinitions.at( aCadstarPartID );
2821}
2822
2823
2826{
2827 wxCHECK( Assignments.Codedefs.RouteCodes.find( aCadstarRouteCodeID )
2828 != Assignments.Codedefs.RouteCodes.end(),
2829 ROUTECODE() );
2830
2831 return Assignments.Codedefs.RouteCodes.at( aCadstarRouteCodeID );
2832}
2833
2834
2835CADSTAR_SCH_ARCHIVE_LOADER::PART::DEFINITION::PIN
2837 const TERMINAL_ID& aTerminalID )
2838{
2839 for( std::pair<PART_DEFINITION_PIN_ID, PART::DEFINITION::PIN> pinPair :
2840 aCadstarPart.Definition.Pins )
2841 {
2842 PART::DEFINITION::PIN partPin = pinPair.second;
2843
2844 if( partPin.TerminalGate == aGateID && partPin.TerminalPin == aTerminalID )
2845 return partPin;
2846 }
2847
2848 return PART::DEFINITION::PIN();
2849}
2850
2851
2870
2872{
2873 if( aCadstarGateID.IsEmpty() )
2874 return 1;
2875
2876 return (int) aCadstarGateID.Upper().GetChar( 0 ) - (int) wxUniChar( 'A' ) + 1;
2877}
2878
2879
2880SPIN_STYLE CADSTAR_SCH_ARCHIVE_LOADER::getSpinStyle( const long long& aCadstarOrientation,
2881 bool aMirror )
2882{
2883 EDA_ANGLE orientation = getAngle( aCadstarOrientation );
2884 SPIN_STYLE spinStyle = getSpinStyle( orientation );
2885
2886 if( aMirror )
2887 {
2888 spinStyle = spinStyle.RotateCCW();
2889 spinStyle = spinStyle.RotateCCW();
2890 }
2891
2892 return spinStyle;
2893}
2894
2895
2897{
2898 SPIN_STYLE spinStyle = SPIN_STYLE::LEFT;
2899
2900 EDA_ANGLE oDeg = aOrientation;
2901 oDeg.Normalize180();
2902
2903 if( oDeg >= -ANGLE_45 && oDeg <= ANGLE_45 )
2904 spinStyle = SPIN_STYLE::RIGHT; // 0deg
2905 else if( oDeg >= ANGLE_45 && oDeg <= ANGLE_135 )
2906 spinStyle = SPIN_STYLE::UP; // 90deg
2907 else if( oDeg >= ANGLE_135 || oDeg <= -ANGLE_135 )
2908 spinStyle = SPIN_STYLE::LEFT; // 180deg
2909 else
2910 spinStyle = SPIN_STYLE::BOTTOM; // 270deg
2911
2912 return spinStyle;
2913}
2914
2915
2918{
2919 switch( aCadstarAlignment )
2920 {
2921 // Change left to right:
2926
2927 //Change right to left:
2931
2932 // Center alignment does not mirror:
2935 case ALIGNMENT::TOPCENTER: return aCadstarAlignment;
2936
2937 // Shouldn't be here
2938 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2939 }
2940}
2941
2942
2945{
2946 switch( aCadstarAlignment )
2947 {
2958
2959 // Shouldn't be here
2960 default: wxFAIL_MSG( "Unknown Cadstar Alignment" ); return aCadstarAlignment;
2961 }
2962}
2963
2964
2966 const TEXTCODE_ID& aCadstarTextCodeID )
2967{
2968 // Ensure we have no Cadstar overbar characters
2969 wxString escapedText = HandleTextOverbar( aKiCadTextItem->GetText() );
2970 aKiCadTextItem->SetText( escapedText );
2971
2972 if( !Assignments.Codedefs.TextCodes.count( aCadstarTextCodeID ) )
2973 return;
2974
2975 TEXTCODE textCode = getTextCode( aCadstarTextCodeID );
2976 int textHeight = KiROUND( (double) getKiCadLength( textCode.Height ) * TXT_HEIGHT_RATIO );
2977 int textWidth = getKiCadLength( textCode.Width );
2978
2979 // The width is zero for all non-cadstar fonts. Using a width equal to 2/3 the height seems
2980 // to work well for most fonts.
2981 if( textWidth == 0 )
2982 textWidth = getKiCadLength( 2LL * textCode.Height / 3LL );
2983
2984 aKiCadTextItem->SetTextWidth( textWidth );
2985 aKiCadTextItem->SetTextHeight( textHeight );
2986
2987#if 0
2988 // EEschema currently supports only normal vs bold for text thickness.
2989 aKiCadTextItem->SetTextThickness( getKiCadLength( textCode.LineWidth ) );
2990#endif
2991
2992 // Must come after SetTextSize()
2993 aKiCadTextItem->SetBold( textCode.Font.Modifier1 == FONT_BOLD );
2994 aKiCadTextItem->SetItalic( textCode.Font.Italic );
2995}
2996
2997
2999 const TEXTCODE_ID& aCadstarTextCodeID,
3000 const ALIGNMENT& aCadstarAlignment,
3001 const JUSTIFICATION& aCadstarJustification,
3002 const long long aCadstarOrientAngle,
3003 bool aMirrored )
3004{
3005 applyTextCodeIfExists( aKiCadTextItem, aCadstarTextCodeID );
3006 aKiCadTextItem->SetTextAngle( getAngle( aCadstarOrientAngle ) );
3007
3008 // Justification ignored for now as not supported in Eeschema, but leaving this code in
3009 // place for future upgrades.
3010 // TODO update this when Eeschema supports justification independent of anchor position.
3011 ALIGNMENT textAlignment = aCadstarAlignment;
3012
3013 // KiCad mirrors the justification and alignment when the symbol is mirrored but CADSTAR
3014 // specifies it post-mirroring. In contrast, if the text item itself is mirrored (not
3015 // supported in KiCad), CADSTAR specifies the alignment and justification pre-mirroring
3016 if( aMirrored )
3017 textAlignment = mirrorX( aCadstarAlignment );
3018
3019 auto setAlignment =
3020 [&]( EDA_TEXT* aText, ALIGNMENT aAlignment )
3021 {
3022 switch( aAlignment )
3023 {
3024 case ALIGNMENT::NO_ALIGNMENT: // Bottom left of the first line
3025 //No exact KiCad equivalent, so lets move the position of the text
3031 break;
3032
3036 break;
3037
3041 break;
3042
3046 break;
3047
3051 break;
3052
3056 break;
3057
3058 case ALIGNMENT::TOPLEFT:
3061 break;
3062
3066 break;
3067
3071 break;
3072 }
3073 };
3074
3075 SPIN_STYLE spin = getSpinStyle( aCadstarOrientAngle, aMirrored );
3076 EDA_ITEM* textEdaItem = dynamic_cast<EDA_ITEM*>( aKiCadTextItem );
3077 wxCHECK( textEdaItem, /* void */ ); // ensure this is a EDA_ITEM
3078
3079 if( textEdaItem->Type() == SCH_FIELD_T )
3080 {
3081 // Spin style not used. All text justifications are permitted. However, only orientations
3082 // of 0 deg or 90 deg are supported
3083 EDA_ANGLE angle = aKiCadTextItem->GetTextAngle();
3084 angle.Normalize();
3085
3086 int quadrant = KiROUND( angle.AsDegrees() / 90.0 );
3087 quadrant %= 4;
3088
3089 switch( quadrant )
3090 {
3091 case 0:
3092 angle = ANGLE_HORIZONTAL;
3093 break;
3094 case 1:
3095 angle = ANGLE_VERTICAL;
3096 break;
3097 case 2:
3098 angle = ANGLE_HORIZONTAL;
3099 textAlignment = rotate180( textAlignment );
3100 break;
3101 case 3:
3102 angle = ANGLE_VERTICAL;
3103 textAlignment = rotate180( textAlignment );
3104 break;
3105 default:
3106 wxFAIL_MSG( "Unknown Quadrant" );
3107 }
3108
3109 aKiCadTextItem->SetTextAngle( angle );
3110 setAlignment( aKiCadTextItem, textAlignment );
3111 }
3112 else if( textEdaItem->Type() == SCH_TEXT_T )
3113 {
3114 // Note spin style in a SCH_TEXT results in a vertical alignment GR_TEXT_V_ALIGN_BOTTOM
3115 // so need to adjust the location of the text element based on Cadstar's original text
3116 // alignment (anchor position).
3117 setAlignment( aKiCadTextItem, textAlignment );
3118 BOX2I bb = textEdaItem->GetBoundingBox();
3119 int off = static_cast<SCH_TEXT*>( aKiCadTextItem )->GetTextOffset();
3120 VECTOR2I pos;
3121
3122 // Change the anchor point of the text item to make it match the same bounding box
3123 // And correct the error introduced by the text offsetting in KiCad
3124 switch( spin )
3125 {
3126 case SPIN_STYLE::BOTTOM: pos = { bb.GetRight() - off, bb.GetTop() }; break;
3127 case SPIN_STYLE::UP: pos = { bb.GetRight() - off, bb.GetBottom() }; break;
3128 case SPIN_STYLE::LEFT: pos = { bb.GetRight() , bb.GetBottom() + off }; break;
3129 case SPIN_STYLE::RIGHT: pos = { bb.GetLeft() , bb.GetBottom() + off }; break;
3130 default: wxFAIL_MSG( "Unexpected Spin Style" ); break;
3131 }
3132
3133 aKiCadTextItem->SetTextPos( pos );
3134
3135 switch( spin )
3136 {
3137 case SPIN_STYLE::RIGHT: // Horiz Normal Orientation
3138 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3139 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3140 break;
3141
3142 case SPIN_STYLE::UP: // Vert Orientation UP
3143 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3144 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_LEFT );
3145 break;
3146
3147 case SPIN_STYLE::LEFT: // Horiz Orientation - Right justified
3148 aKiCadTextItem->SetTextAngle( ANGLE_HORIZONTAL );
3149 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3150 break;
3151
3152 case SPIN_STYLE::BOTTOM: // Vert Orientation BOTTOM
3153 aKiCadTextItem->SetTextAngle( ANGLE_VERTICAL );
3154 aKiCadTextItem->SetHorizJustify( GR_TEXT_H_ALIGN_RIGHT );
3155 break;
3156
3157 default:
3158 wxFAIL_MSG( "Unexpected Spin Style" );
3159 break;
3160 }
3161
3162 aKiCadTextItem->SetVertJustify( GR_TEXT_V_ALIGN_BOTTOM );
3163 }
3164 else if( SCH_LABEL_BASE* label = dynamic_cast<SCH_LABEL_BASE*>( aKiCadTextItem ) )
3165 {
3166 // We don't want to change position of net labels as that would break connectivity
3167 label->SetSpinStyle( spin );
3168 }
3169 else
3170 {
3171 wxFAIL_MSG( "Unexpected item type" );
3172 }
3173}
3174
3175
3177{
3178 SCH_TEXT* kiTxt = new SCH_TEXT();
3179
3180 kiTxt->SetParent( m_schematic ); // set to the schematic for now to avoid asserts
3181 kiTxt->SetPosition( getKiCadPoint( aCadstarTextElement.Position ) );
3182 kiTxt->SetText( aCadstarTextElement.Text );
3183
3184 applyTextSettings( kiTxt, aCadstarTextElement.TextCodeID, aCadstarTextElement.Alignment,
3185 aCadstarTextElement.Justification, aCadstarTextElement.OrientAngle,
3186 aCadstarTextElement.Mirror );
3187
3188 return kiTxt;
3189}
3190
3191
3193 long long aScalingFactorNumerator,
3194 long long aScalingFactorDenominator )
3195{
3196 LIB_SYMBOL* retval = new LIB_SYMBOL( *aSymbol );
3197
3198 if( aScalingFactorNumerator == aScalingFactorDenominator )
3199 return retval; // 1:1 scale, nothing to do
3200
3201 auto scaleLen =
3202 [&]( int aLength ) -> int
3203 {
3204 return( aLength * aScalingFactorNumerator ) / aScalingFactorDenominator;
3205 };
3206
3207 auto scalePt =
3208 [&]( VECTOR2I aCoord ) -> VECTOR2I
3209 {
3210 return VECTOR2I( scaleLen( aCoord.x ), scaleLen( aCoord.y ) );
3211 };
3212
3213 auto scaleSize =
3214 [&]( VECTOR2I aSize ) -> VECTOR2I
3215 {
3216 return VECTOR2I( scaleLen( aSize.x ), scaleLen( aSize.y ) );
3217 };
3218
3219 LIB_ITEMS_CONTAINER& items = retval->GetDrawItems();
3220
3221 for( SCH_ITEM& item : items )
3222 {
3223 switch( item.Type() )
3224 {
3226 {
3227 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( item );
3228
3229 if( shape.GetShape() == SHAPE_T::ARC )
3230 {
3231 shape.SetPosition( scalePt( shape.GetPosition() ) );
3232 shape.SetStart( scalePt( shape.GetStart() ) );
3233 shape.SetEnd( scalePt( shape.GetEnd() ) );
3234 }
3235 else if( shape.GetShape() == SHAPE_T::POLY )
3236 {
3237 SHAPE_LINE_CHAIN& poly = shape.GetPolyShape().Outline( 0 );
3238
3239 for( size_t ii = 0; ii < poly.GetPointCount(); ++ii )
3240 poly.SetPoint( ii, scalePt( poly.CPoint( ii ) ) );
3241 }
3242 break;
3243 }
3244
3245 case KICAD_T::SCH_PIN_T:
3246 {
3247 SCH_PIN& pin = static_cast<SCH_PIN&>( item );
3248
3249 pin.SetPosition( scalePt( pin.GetPosition() ) );
3250 pin.SetLength( scaleLen( pin.GetLength() ) );
3251 break;
3252 }
3253
3255 {
3256 SCH_TEXT& txt = static_cast<SCH_TEXT&>( item );
3257
3258 txt.SetPosition( scalePt( txt.GetPosition() ) );
3259 txt.SetTextSize( scaleSize( txt.GetTextSize() ) );
3260 break;
3261 }
3262
3263 default:
3264 break;
3265 }
3266 }
3267
3268 return retval;
3269}
3270
3271
3272void CADSTAR_SCH_ARCHIVE_LOADER::fixUpLibraryPins( LIB_SYMBOL* aSymbolToFix, int aGateNumber )
3273{
3274 auto compLambda =
3275 []( const VECTOR2I& aA, const VECTOR2I& aB )
3276 {
3277 return LexicographicalCompare( aA, aB ) < 0;
3278 };
3279
3280 // Store a list of vertical or horizontal segments in the symbol
3281 // Note: Need the custom comparison function to ensure the map is sorted correctly
3282 std::map<VECTOR2I, SHAPE_LINE_CHAIN, decltype( compLambda )> uniqueSegments( compLambda );
3283
3284 LIB_ITEMS_CONTAINER::ITERATOR shapeIt = aSymbolToFix->GetDrawItems().begin( SCH_SHAPE_T );
3285
3286 for( ; shapeIt != aSymbolToFix->GetDrawItems().end( SCH_SHAPE_T ); ++shapeIt )
3287 {
3288 SCH_SHAPE& shape = static_cast<SCH_SHAPE&>( *shapeIt );
3289
3290 if( aGateNumber > 0 && shape.GetUnit() != aGateNumber )
3291 continue;
3292
3293 if( shape.GetShape() != SHAPE_T::POLY )
3294 continue;
3295
3296 SHAPE_LINE_CHAIN poly = shape.GetPolyShape().Outline( 0 );
3297
3298 if( poly.GetPointCount() == 2 )
3299 {
3300 VECTOR2I pt0 = poly.CPoint( 0 );
3301 VECTOR2I pt1 = poly.CPoint( 1 );
3302
3303 if( pt0 != pt1 && uniqueSegments.count( pt0 ) == 0 && uniqueSegments.count( pt1 ) == 0 )
3304 {
3305 // we are only interested in vertical or horizontal segments
3306 if( pt0.x == pt1.x || pt0.y == pt1.y )
3307 {
3308 uniqueSegments.insert( { pt0, poly } );
3309 uniqueSegments.insert( { pt1, poly } );
3310 }
3311 }
3312 }
3313 }
3314
3315 for( SCH_PIN* pin : aSymbolToFix->GetGraphicalPins( aGateNumber, 0 ) )
3316 {
3317 auto setPinOrientation =
3318 [&]( const EDA_ANGLE& aAngle )
3319 {
3320 EDA_ANGLE angle( aAngle );
3321 angle.Normalize180();
3322
3323 if( angle >= -ANGLE_45 && angle <= ANGLE_45 )
3324 pin->SetOrientation( PIN_ORIENTATION::PIN_RIGHT ); // 0 degrees
3325 else if( angle >= ANGLE_45 && angle <= ANGLE_135 )
3326 pin->SetOrientation( PIN_ORIENTATION::PIN_UP ); // 90 degrees
3327 else if( angle >= ANGLE_135 || angle <= -ANGLE_135 )
3328 pin->SetOrientation( PIN_ORIENTATION::PIN_LEFT ); // 180 degrees
3329 else
3330 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN ); // -90 degrees
3331 };
3332
3333 if( uniqueSegments.count( pin->GetPosition() ) )
3334 {
3335 SHAPE_LINE_CHAIN& poly = uniqueSegments.at( pin->GetPosition() );
3336
3337 VECTOR2I otherPt = poly.CPoint( 0 );
3338
3339 if( otherPt == pin->GetPosition() )
3340 otherPt = poly.CPoint( 1 );
3341
3342 VECTOR2I vec( otherPt - pin->GetPosition() );
3343
3344 pin->SetLength( vec.EuclideanNorm() );
3345 setPinOrientation( EDA_ANGLE( vec ) );
3346 }
3347 }
3348}
3349
3350
3351std::pair<VECTOR2I, VECTOR2I>
3353{
3354 VECTOR2I upperLeft( Assignments.Settings.DesignLimit.x, 0 );
3355 VECTOR2I lowerRight( 0, Assignments.Settings.DesignLimit.y );
3356
3357 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3358 {
3359 if( upperLeft.x > v.End.x )
3360 upperLeft.x = v.End.x;
3361
3362 if( upperLeft.y < v.End.y )
3363 upperLeft.y = v.End.y;
3364
3365 if( lowerRight.x < v.End.x )
3366 lowerRight.x = v.End.x;
3367
3368 if( lowerRight.y > v.End.y )
3369 lowerRight.y = v.End.y;
3370 }
3371
3372 for( CUTOUT cutout : aCadstarFigure.Shape.Cutouts )
3373 {
3374 for( const VERTEX& v : aCadstarFigure.Shape.Vertices )
3375 {
3376 if( upperLeft.x > v.End.x )
3377 upperLeft.x = v.End.x;
3378
3379 if( upperLeft.y < v.End.y )
3380 upperLeft.y = v.End.y;
3381
3382 if( lowerRight.x < v.End.x )
3383 lowerRight.x = v.End.x;
3384
3385 if( lowerRight.y > v.End.y )
3386 lowerRight.y = v.End.y;
3387 }
3388 }
3389
3390 VECTOR2I upperLeftKiCad = getKiCadPoint( upperLeft );
3391 VECTOR2I lowerRightKiCad = getKiCadPoint( lowerRight );
3392
3393 VECTOR2I size = lowerRightKiCad - upperLeftKiCad;
3394
3395 return { upperLeftKiCad, VECTOR2I( abs( size.x ), abs( size.y ) ) };
3396}
3397
3398
3400{
3401 VECTOR2I retval;
3402
3403 retval.x = getKiCadLength( aCadstarPoint.x - m_designCenter.x );
3404 retval.y = -getKiCadLength( aCadstarPoint.y - m_designCenter.y );
3405
3406 return retval;
3407}
3408
3409
3411 const VECTOR2I& aCadstarCentre )
3412{
3413 VECTOR2I retval;
3414
3415 retval.x = getKiCadLength( aCadstarPoint.x - aCadstarCentre.x );
3416 retval.y = -getKiCadLength( aCadstarPoint.y - aCadstarCentre.y );
3417
3418 return retval;
3419}
3420
3421
3423 const VECTOR2I& aMoveVector,
3424 const EDA_ANGLE& aRotation,
3425 const double& aScalingFactor,
3426 const VECTOR2I& aTransformCentre,
3427 const bool& aMirrorInvert )
3428{
3429 VECTOR2I retVal = aPoint;
3430
3431 if( aScalingFactor != 1.0 )
3432 {
3433 //scale point
3434 retVal -= aTransformCentre;
3435 retVal.x = KiROUND( retVal.x * aScalingFactor );
3436 retVal.y = KiROUND( retVal.y * aScalingFactor );
3437 retVal += aTransformCentre;
3438 }
3439
3440 if( aMirrorInvert )
3441 MIRROR( retVal.x, aTransformCentre.x );
3442
3443 if( !aRotation.IsZero() )
3444 RotatePoint( retVal, aTransformCentre, aRotation );
3445
3446 if( aMoveVector != VECTOR2I{ 0, 0 } )
3447 retVal += aMoveVector;
3448
3449 return retVal;
3450}
3451
3452
3454{
3455 return sqrt( ( (double) aPoint.x * (double) aPoint.x )
3456 + ( (double) aPoint.y * (double) aPoint.y ) );
3457}
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
static SCH_FIELD * addNewFieldToSymbol(const wxString &aFieldName, std::unique_ptr< LIB_SYMBOL > &aKiCadSymbol)
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.
PART getPart(const PART_ID &aCadstarPartID)
std::vector< LAYER_ID > findOrphanSheets()
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 setFootprintOnSymbol(std::unique_ptr< LIB_SYMBOL > &aKiCadSymbol, const wxString &aFootprintName, const wxString &aFootprintAlternate)
void applyTextCodeIfExists(EDA_TEXT *aKiCadTextItem, const TEXTCODE_ID &aCadstarTextCodeID)
int getSheetNumber(const LAYER_ID &aCadstarSheetID)
void copySymbolItems(std::unique_ptr< LIB_SYMBOL > &aSourceSym, std::unique_ptr< LIB_SYMBOL > &aDestSym, int aDestUnit, bool aOverrideFields=true)
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.
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:80
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.
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:759
wxString GetName() const override
Definition lib_symbol.h:142
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
SCH_FIELD & GetValueField()
Return reference to the value field.
Definition lib_symbol.h:378
std::vector< SCH_PIN * > GetPinsByNumber(const wxString &aNumber, int aUnit=0, int aBodyStyle=0)
Return all pin objects with the requested pin aNumber.
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:382
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:62
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:914
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
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:447
@ LAYER_DEVICE
Definition layer_ids.h:464
@ LAYER_WIRE
Definition layer_ids.h:450
@ LAYER_NOTES
Definition layer_ids.h:465
@ LAYER_BUS
Definition layer_ids.h:451
MULTIVECTOR< SCH_ITEM, SCH_SHAPE_T, SCH_PIN_T > LIB_ITEMS_CONTAINER
Definition lib_symbol.h:49
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
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.