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