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