KiCad PCB EDA Suite
Loading...
Searching...
No Matches
pads_sch_symbol_builder.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) 2025 KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 3
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
21
22#include <lib_symbol.h>
23#include <sch_shape.h>
24#include <sch_pin.h>
25#include <sch_text.h>
26#include <pin_type.h>
27#include <layer_ids.h>
28#include <sch_screen.h>
29#include <stroke_params.h>
30
31#include <advanced_config.h>
32#include <io/pads/pads_common.h>
33
34#include <algorithm>
35#include <cctype>
36#include <cmath>
37
38
39namespace PADS_SCH
40{
41
46
47
51
52
53int PADS_SCH_SYMBOL_BUILDER::toKiCadUnits( double aPadsValue ) const
54{
55 // Convert from PADS units to KiCad internal units (nanometers)
56 // PADS uses mils by default, KiCad schematic uses schIUScale.MilsToIU()
57
58 double milsValue = aPadsValue;
59
60 switch( m_params.units )
61 {
62 case UNIT_TYPE::MILS:
63 milsValue = aPadsValue;
64 break;
65
67 // mm to mils: 1 mm = 39.37 mils
68 milsValue = aPadsValue * 39.3701;
69 break;
70
72 // inches to mils
73 milsValue = aPadsValue * 1000.0;
74 break;
75 }
76
77 return schIUScale.MilsToIU( milsValue );
78}
79
80
82{
83 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aSymbolDef.name ) );
84
85 // Add graphics
86 for( const auto& graphic : aSymbolDef.graphics )
87 {
88 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
89
90 for( SCH_SHAPE* shape : shapes )
91 libSymbol->AddDrawItem( shape );
92 }
93
94 // Add pins
95 for( const auto& pin : aSymbolDef.pins )
96 {
97 SCH_PIN* schPin = createPin( pin, libSymbol );
98
99 if( schPin )
100 libSymbol->AddDrawItem( schPin );
101 }
102
103 // Add embedded text labels
104 for( const auto& text : aSymbolDef.texts )
105 {
106 if( text.content.empty() )
107 continue;
108
109 SCH_TEXT* schText = new SCH_TEXT(
110 VECTOR2I( toKiCadUnits( text.position.x ), -toKiCadUnits( text.position.y ) ),
111 wxString::FromUTF8( text.content ), LAYER_DEVICE );
112
113 if( text.size > 0.0 )
114 {
115 int scaledSize = toKiCadUnits( text.size );
116 int charHeight = static_cast<int>(
118 int charWidth = static_cast<int>(
120 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
121 }
122
123 if( text.rotation != 0.0 )
124 schText->SetTextAngleDegrees( text.rotation );
125
126 libSymbol->AddDrawItem( schText );
127 }
128
129 libSymbol->SetShowPinNumbers( false );
130 libSymbol->SetShowPinNames( false );
131
132 return libSymbol;
133}
134
135
137{
138 auto it = m_symbolCache.find( aSymbolDef.name );
139
140 if( it != m_symbolCache.end() )
141 return it->second.get();
142
143 LIB_SYMBOL* newSymbol = BuildSymbol( aSymbolDef );
144 m_symbolCache[aSymbolDef.name] = std::unique_ptr<LIB_SYMBOL>( newSymbol );
145
146 return newSymbol;
147}
148
149
151 const PARTTYPE_DEF& aPartType, const std::vector<SYMBOL_DEF>& aSymbolDefs )
152{
153 // Build a lookup from CAEDECAL name to definition
154 std::map<std::string, const SYMBOL_DEF*> symDefByName;
155
156 for( const auto& sd : aSymbolDefs )
157 symDefByName[sd.name] = &sd;
158
159 int gateCount = static_cast<int>( aPartType.gates.size() );
160 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aPartType.name ) );
161 libSymbol->SetUnitCount( gateCount, false );
162 libSymbol->LockUnits( true );
163
164 for( int gi = 0; gi < gateCount; gi++ )
165 {
166 const GATE_DEF& gate = aPartType.gates[gi];
167 int unit = gi + 1;
168
169 // Resolve the CAEDECAL for this gate
170 std::string decalName;
171
172 if( !gate.decal_names.empty() )
173 decalName = gate.decal_names[0];
174
175 auto sdIt = symDefByName.find( decalName );
176
177 if( sdIt == symDefByName.end() )
178 continue;
179
180 const SYMBOL_DEF& symDef = *sdIt->second;
181
182 // Add graphics for this unit
183 for( const auto& graphic : symDef.graphics )
184 {
185 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
186
187 for( SCH_SHAPE* shape : shapes )
188 {
189 shape->SetUnit( unit );
190 libSymbol->AddDrawItem( shape );
191 }
192 }
193
194 // Add pins with PARTTYPE overrides
195 for( size_t p = 0; p < symDef.pins.size(); p++ )
196 {
197 SYMBOL_PIN pin = symDef.pins[p];
198
199 if( p < gate.pins.size() )
200 {
201 pin.name = gate.pins[p].pin_name;
202 pin.number = gate.pins[p].pin_id;
203
204 if( gate.pins[p].pin_type != 0 )
205 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( gate.pins[p].pin_type );
206 }
207
208 SCH_PIN* schPin = createPin( pin, libSymbol );
209
210 if( schPin )
211 {
212 schPin->SetUnit( unit );
213 libSymbol->AddDrawItem( schPin );
214 }
215 }
216
217 // Add embedded text labels for this unit
218 for( const auto& text : symDef.texts )
219 {
220 if( text.content.empty() )
221 continue;
222
223 SCH_TEXT* schText = new SCH_TEXT(
224 VECTOR2I( toKiCadUnits( text.position.x ),
225 -toKiCadUnits( text.position.y ) ),
226 wxString::FromUTF8( text.content ), LAYER_DEVICE );
227
228 if( text.size > 0.0 )
229 {
230 int scaledSize = toKiCadUnits( text.size );
231 int charHeight = static_cast<int>(
233 int charWidth = static_cast<int>(
235 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
236 }
237
238 if( text.rotation != 0.0 )
239 schText->SetTextAngleDegrees( text.rotation );
240
241 schText->SetUnit( unit );
242 libSymbol->AddDrawItem( schText );
243 }
244 }
245
246 libSymbol->SetShowPinNumbers( true );
247 libSymbol->SetShowPinNames( true );
248
249 return libSymbol;
250}
251
252
254 const PARTTYPE_DEF& aPartType, const std::vector<SYMBOL_DEF>& aSymbolDefs )
255{
256 // Use a prefixed key to avoid collision with CAEDECAL symbols that may
257 // share the same name as the PARTTYPE (e.g. both named "TL082").
258 std::string cacheKey = "parttype:" + aPartType.name;
259 auto it = m_symbolCache.find( cacheKey );
260
261 if( it != m_symbolCache.end() )
262 return it->second.get();
263
264 LIB_SYMBOL* newSymbol = BuildMultiUnitSymbol( aPartType, aSymbolDefs );
265 m_symbolCache[cacheKey] = std::unique_ptr<LIB_SYMBOL>( newSymbol );
266
267 return newSymbol;
268}
269
270
272 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef )
273{
274 // Cache by PARTTYPE + CAEDECAL pair. A single-gate PARTTYPE with multiple decal
275 // variants (e.g. horizontal vs vertical resistor) needs a separate LIB_SYMBOL per
276 // variant because the graphics and pin positions differ.
277 std::string cacheKey = aPartType.name + ":" + aSymbolDef.name;
278 auto it = m_symbolCache.find( cacheKey );
279
280 if( it != m_symbolCache.end() )
281 return it->second.get();
282
283 if( aPartType.gates.empty() )
284 return nullptr;
285
286 // Build from the CAEDECAL then apply pin overrides from the PARTTYPE gate
287 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aSymbolDef.name ) );
288
289 for( const auto& graphic : aSymbolDef.graphics )
290 {
291 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
292
293 for( SCH_SHAPE* shape : shapes )
294 libSymbol->AddDrawItem( shape );
295 }
296
297 const GATE_DEF& gate = aPartType.gates[0];
298
299 for( size_t p = 0; p < aSymbolDef.pins.size(); p++ )
300 {
301 SYMBOL_PIN pin = aSymbolDef.pins[p];
302
303 if( p < gate.pins.size() )
304 {
305 pin.name = gate.pins[p].pin_name;
306 pin.number = gate.pins[p].pin_id;
307
308 if( gate.pins[p].pin_type != 0 )
309 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( gate.pins[p].pin_type );
310 }
311
312 SCH_PIN* schPin = createPin( pin, libSymbol );
313
314 if( schPin )
315 libSymbol->AddDrawItem( schPin );
316 }
317
318 for( const auto& text : aSymbolDef.texts )
319 {
320 if( text.content.empty() )
321 continue;
322
323 SCH_TEXT* schText = new SCH_TEXT(
324 VECTOR2I( toKiCadUnits( text.position.x ),
325 -toKiCadUnits( text.position.y ) ),
326 wxString::FromUTF8( text.content ), LAYER_DEVICE );
327
328 if( text.size > 0.0 )
329 {
330 int scaledSize = toKiCadUnits( text.size );
331 int charHeight = static_cast<int>(
333 int charWidth = static_cast<int>(
335 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
336 }
337
338 if( text.rotation != 0.0 )
339 schText->SetTextAngleDegrees( text.rotation );
340
341 libSymbol->AddDrawItem( schText );
342 }
343
344 // Show pin names/numbers if any gate pin has an explicit name
345 bool hasPinNames = false;
346
347 for( const auto& pin : gate.pins )
348 {
349 if( !pin.pin_name.empty() )
350 {
351 hasPinNames = true;
352 break;
353 }
354 }
355
356 libSymbol->SetShowPinNumbers( hasPinNames );
357 libSymbol->SetShowPinNames( hasPinNames );
358
359 m_symbolCache[cacheKey] = std::unique_ptr<LIB_SYMBOL>( libSymbol );
360
361 return libSymbol;
362}
363
364
366 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef,
367 const std::string& aPinNumber )
368{
369 std::string cacheKey = aPartType.name + ":" + aSymbolDef.name + ":" + aPinNumber;
370 auto it = m_symbolCache.find( cacheKey );
371
372 if( it != m_symbolCache.end() )
373 return it->second.get();
374
375 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aSymbolDef.name ) );
376
377 for( const auto& graphic : aSymbolDef.graphics )
378 {
379 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
380
381 for( SCH_SHAPE* shape : shapes )
382 libSymbol->AddDrawItem( shape );
383 }
384
385 // Create pin(s) from the CAEDECAL but override the pin number
386 for( size_t p = 0; p < aSymbolDef.pins.size(); p++ )
387 {
388 SYMBOL_PIN pin = aSymbolDef.pins[p];
389 pin.number = aPinNumber;
390
391 if( !aPartType.gates.empty() && p < aPartType.gates[0].pins.size() )
392 {
393 pin.name = aPartType.gates[0].pins[p].pin_name;
394
395 if( aPartType.gates[0].pins[p].pin_type != 0 )
396 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( aPartType.gates[0].pins[p].pin_type );
397 }
398
399 SCH_PIN* schPin = createPin( pin, libSymbol );
400
401 if( schPin )
402 libSymbol->AddDrawItem( schPin );
403 }
404
405 for( const auto& text : aSymbolDef.texts )
406 {
407 if( text.content.empty() )
408 continue;
409
410 SCH_TEXT* schText = new SCH_TEXT(
411 VECTOR2I( toKiCadUnits( text.position.x ),
412 -toKiCadUnits( text.position.y ) ),
413 wxString::FromUTF8( text.content ), LAYER_DEVICE );
414
415 if( text.size > 0.0 )
416 {
417 int scaledSize = toKiCadUnits( text.size );
418 int charHeight = static_cast<int>(
420 int charWidth = static_cast<int>(
422 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
423 }
424
425 if( text.rotation != 0.0 )
426 schText->SetTextAngleDegrees( text.rotation );
427
428 libSymbol->AddDrawItem( schText );
429 }
430
431 libSymbol->SetShowPinNumbers( false );
432 libSymbol->SetShowPinNames( false );
433
434 m_symbolCache[cacheKey] = std::unique_ptr<LIB_SYMBOL>( libSymbol );
435
436 return libSymbol;
437}
438
439
441 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef,
442 const std::vector<std::string>& aPinNumbers )
443{
444 int unitCount = static_cast<int>( aPinNumbers.size() );
445 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aPartType.name ) );
446 libSymbol->SetUnitCount( unitCount, false );
447 libSymbol->LockUnits( true );
448
449 // Build a lookup from pin ID to PARTTYPE pin definition
450 std::map<std::string, const PARTTYPE_PIN*> ptPinById;
451
452 if( !aPartType.gates.empty() )
453 {
454 for( const auto& ptPin : aPartType.gates[0].pins )
455 ptPinById[ptPin.pin_id] = &ptPin;
456 }
457
458 for( int u = 0; u < unitCount; u++ )
459 {
460 int unit = u + 1;
461
462 for( const auto& graphic : aSymbolDef.graphics )
463 {
464 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
465
466 for( SCH_SHAPE* shape : shapes )
467 {
468 shape->SetUnit( unit );
469 libSymbol->AddDrawItem( shape );
470 }
471 }
472
473 // One pin per unit with the correct pin number
474 if( !aSymbolDef.pins.empty() )
475 {
476 SYMBOL_PIN pin = aSymbolDef.pins[0];
477 pin.number = aPinNumbers[u];
478
479 auto ptPinIt = ptPinById.find( aPinNumbers[u] );
480
481 if( ptPinIt != ptPinById.end() )
482 {
483 if( ptPinIt->second->pin_type != 0 )
484 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( ptPinIt->second->pin_type );
485
486 if( !ptPinIt->second->pin_name.empty() )
487 pin.name = ptPinIt->second->pin_name;
488 }
489
490 SCH_PIN* schPin = createPin( pin, libSymbol );
491
492 if( schPin )
493 {
494 schPin->SetUnit( unit );
495 libSymbol->AddDrawItem( schPin );
496 }
497 }
498
499 for( const auto& text : aSymbolDef.texts )
500 {
501 if( text.content.empty() )
502 continue;
503
504 SCH_TEXT* schText = new SCH_TEXT(
505 VECTOR2I( toKiCadUnits( text.position.x ),
506 -toKiCadUnits( text.position.y ) ),
507 wxString::FromUTF8( text.content ), LAYER_DEVICE );
508
509 if( text.size > 0.0 )
510 {
511 int scaledSize = toKiCadUnits( text.size );
512 int charHeight = static_cast<int>(
514 int charWidth = static_cast<int>(
516 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
517 }
518
519 if( text.rotation != 0.0 )
520 schText->SetTextAngleDegrees( text.rotation );
521
522 schText->SetUnit( unit );
523 libSymbol->AddDrawItem( schText );
524 }
525 }
526
527 libSymbol->SetShowPinNumbers( true );
528 libSymbol->SetShowPinNames( false );
529
530 return libSymbol;
531}
532
533
535 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef,
536 const std::vector<std::string>& aPinNumbers, const std::string& aCacheKey )
537{
538 auto it = m_symbolCache.find( aCacheKey );
539
540 if( it != m_symbolCache.end() )
541 return it->second.get();
542
543 LIB_SYMBOL* newSymbol = BuildMultiUnitConnectorSymbol( aPartType, aSymbolDef, aPinNumbers );
544 m_symbolCache[aCacheKey] = std::unique_ptr<LIB_SYMBOL>( newSymbol );
545
546 return newSymbol;
547}
548
549
550bool PADS_SCH_SYMBOL_BUILDER::HasSymbol( const std::string& aName ) const
551{
552 return m_symbolCache.find( aName ) != m_symbolCache.end();
553}
554
555
556LIB_SYMBOL* PADS_SCH_SYMBOL_BUILDER::GetSymbol( const std::string& aName ) const
557{
558 auto it = m_symbolCache.find( aName );
559
560 if( it != m_symbolCache.end() )
561 return it->second.get();
562
563 return nullptr;
564}
565
566
568{
569 SCH_SHAPE* shape = nullptr;
570
571 switch( aGraphic.type )
572 {
575 {
576 bool hasArcs = false;
577
578 for( const auto& pt : aGraphic.points )
579 {
580 if( pt.arc.has_value() )
581 {
582 hasArcs = true;
583 break;
584 }
585 }
586
587 if( !hasArcs )
588 {
589 shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
590
591 for( const auto& pt : aGraphic.points )
592 shape->AddPoint( VECTOR2I( toKiCadUnits( pt.coord.x ),
593 -toKiCadUnits( pt.coord.y ) ) );
594 }
595 else
596 {
597 // Mixed line/arc path requires multiple shapes. Return nullptr here and let
598 // BuildSymbol handle this via createShapes() instead.
599 return nullptr;
600 }
601
602 break;
603 }
604
606 {
608
609 if( aGraphic.points.size() >= 2 )
610 {
611 VECTOR2I start( toKiCadUnits( aGraphic.points[0].coord.x ),
612 -toKiCadUnits( aGraphic.points[0].coord.y ) );
613 VECTOR2I end( toKiCadUnits( aGraphic.points[1].coord.x ),
614 -toKiCadUnits( aGraphic.points[1].coord.y ) );
615
616 shape->SetStart( start );
617 shape->SetEnd( end );
618 }
619
620 break;
621 }
622
624 {
625 shape = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
626
627 VECTOR2I center( toKiCadUnits( aGraphic.center.x ), -toKiCadUnits( aGraphic.center.y ) );
628 int radius = toKiCadUnits( aGraphic.radius );
629
630 shape->SetStart( center );
631 shape->SetEnd( VECTOR2I( center.x + radius, center.y ) );
632
633 break;
634 }
635
637 {
638 shape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
639
640 VECTOR2I center( toKiCadUnits( aGraphic.center.x ), -toKiCadUnits( aGraphic.center.y ) );
641 int radius = toKiCadUnits( aGraphic.radius );
642
643 // Convert angles from PADS format to KiCad
644 // PADS uses degrees, KiCad uses tenths of degrees for arc definition
645 double startAngle = aGraphic.start_angle * M_PI / 180.0;
646 double endAngle = aGraphic.end_angle * M_PI / 180.0;
647
648 VECTOR2I startPt( center.x + radius * cos( startAngle ),
649 center.y - radius * sin( startAngle ) );
650 VECTOR2I endPt( center.x + radius * cos( endAngle ),
651 center.y - radius * sin( endAngle ) );
652
653 shape->SetStart( startPt );
654 shape->SetEnd( endPt );
655 shape->SetCenter( center );
656
657 break;
658 }
659 }
660
661 if( shape )
662 {
663 int lineWidth = toKiCadUnits( aGraphic.line_width );
664
665 if( lineWidth == 0 )
666 lineWidth = toKiCadUnits( m_params.line_width );
667
668 shape->SetStroke( STROKE_PARAMS( lineWidth, PADS_COMMON::PadsLineStyleToKiCad( aGraphic.line_style ) ) );
669
670 if( aGraphic.filled )
672 }
673
674 return shape;
675}
676
677
678std::vector<SCH_SHAPE*> PADS_SCH_SYMBOL_BUILDER::createShapes( const SYMBOL_GRAPHIC& aGraphic )
679{
680 std::vector<SCH_SHAPE*> result;
681
682 // Try the simple single-shape path first
683 SCH_SHAPE* single = createShape( aGraphic );
684
685 if( single )
686 {
687 result.push_back( single );
688 return result;
689 }
690
691 // Mixed line/arc path: emit individual segments
692 int lineWidth = toKiCadUnits( aGraphic.line_width );
693
694 if( lineWidth == 0 )
695 lineWidth = toKiCadUnits( m_params.line_width );
696
698
699 for( size_t i = 0; i + 1 < aGraphic.points.size(); i++ )
700 {
701 const GRAPHIC_POINT& cur = aGraphic.points[i];
702 const GRAPHIC_POINT& next = aGraphic.points[i + 1];
703
704 VECTOR2I startPt( toKiCadUnits( cur.coord.x ), -toKiCadUnits( cur.coord.y ) );
705 VECTOR2I endPt( toKiCadUnits( next.coord.x ), -toKiCadUnits( next.coord.y ) );
706
707 if( cur.arc.has_value() )
708 {
709 const ARC_DATA& ad = *cur.arc;
710 double cx = ( ad.bbox_x1 + ad.bbox_x2 ) / 2.0;
711 double cy = ( ad.bbox_y1 + ad.bbox_y2 ) / 2.0;
712 VECTOR2I center( toKiCadUnits( cx ), -toKiCadUnits( cy ) );
713
714 // Compute the arc midpoint on the circle between start and end.
715 // Use vector math: midpoint of arc = center + R * normalize(midvector)
716 // where midvector = (start - center) + (end - center)
717 double sx = startPt.x - center.x;
718 double sy = startPt.y - center.y;
719 double ex = endPt.x - center.x;
720 double ey = endPt.y - center.y;
721 double radius = std::sqrt( sx * sx + sy * sy );
722
723 double mx = sx + ex;
724 double my = sy + ey;
725 double mlen = std::sqrt( mx * mx + my * my );
726
727 VECTOR2I midPt;
728
729 if( mlen > 0.001 )
730 {
731 midPt.x = center.x + static_cast<int>( radius * mx / mlen );
732 midPt.y = center.y + static_cast<int>( radius * my / mlen );
733 }
734 else
735 {
736 // Start and end are diametrically opposite, pick perpendicular direction
737 midPt.x = center.x + static_cast<int>( -sy * radius / std::max( radius, 1.0 ) );
738 midPt.y = center.y + static_cast<int>( sx * radius / std::max( radius, 1.0 ) );
739 }
740
741 // The initial midpoint is always on the minor arc side (between start
742 // and end radii). Flip to the major arc side when the sweep exceeds
743 // 180 degrees. The sign of the angle encodes CW/CCW direction in PADS
744 // but does not affect which semicircle the arc occupies.
745 if( std::abs( ad.angle ) > 1800 )
746 {
747 midPt.x = 2 * center.x - midPt.x;
748 midPt.y = 2 * center.y - midPt.y;
749 }
750
752 arc->SetArcGeometry( startPt, midPt, endPt );
753 arc->SetStroke( STROKE_PARAMS( lineWidth, lineStyle ) );
754
755 if( aGraphic.filled )
757
758 result.push_back( arc );
759 }
760 else
761 {
762 if( startPt == endPt )
763 continue;
764
766 line->AddPoint( startPt );
767 line->AddPoint( endPt );
768 line->SetStroke( STROKE_PARAMS( lineWidth, lineStyle ) );
769
770 if( aGraphic.filled )
772
773 result.push_back( line );
774 }
775 }
776
777 return result;
778}
779
780
782{
783 SCH_PIN* pin = new SCH_PIN( aParent );
784
785 // Set pin name and number
786 pin->SetName( wxString::FromUTF8( aPin.name ) );
787 pin->SetNumber( wxString::FromUTF8( aPin.number ) );
788
789 // Set pin position (end point where wire connects)
790 VECTOR2I pos( toKiCadUnits( aPin.position.x ), -toKiCadUnits( aPin.position.y ) );
791 pin->SetPosition( pos );
792
793 // Set pin length
794 int length = toKiCadUnits( aPin.length );
795 pin->SetLength( length );
796
797 // Determine pin orientation from the T-line angle and side fields.
798 // The angle indicates pin text rotation (0=horizontal, 90=vertical) while
799 // the side field indicates which edge of the symbol body the pin is on.
800 // Pin decal names containing "VRT" indicate perpendicular pins.
802 bool isVerticalDecal = ( aPin.pin_decal_name.find( "VRT" ) != std::string::npos );
803 int angle = static_cast<int>( aPin.rotation ) % 360;
804
805 if( isVerticalDecal )
806 {
807 orientation = ( aPin.side == 2 ) ? PIN_ORIENTATION::PIN_UP
809 }
810 else if( angle >= 45 && angle < 135 )
811 {
812 // Sides 0,1 (horizontal edges) point up; sides 2,3 (vertical edges) point down
813 orientation = ( aPin.side >= 2 ) ? PIN_ORIENTATION::PIN_DOWN
815 }
816 else if( angle >= 225 && angle < 315 )
817 {
818 orientation = ( aPin.side >= 2 ) ? PIN_ORIENTATION::PIN_UP
820 }
821 else if( angle >= 135 && angle < 225 )
822 {
823 orientation = ( aPin.side & 1 ) ? PIN_ORIENTATION::PIN_RIGHT
825 }
826 else
827 {
828 orientation = ( aPin.side & 1 ) ? PIN_ORIENTATION::PIN_LEFT
830 }
831
832 pin->SetOrientation( orientation );
833
834 // Set electrical type
835 ELECTRICAL_PINTYPE pinType = static_cast<ELECTRICAL_PINTYPE>( mapPinType( aPin.type ) );
836 pin->SetType( pinType );
837
838 // Set graphic style
840
841 if( aPin.inverted )
843 else if( aPin.clock )
844 pinShape = GRAPHIC_PINSHAPE::CLOCK;
845
846 pin->SetShape( pinShape );
847
848 int pinTextSize = schIUScale.MilsToIU( 50 );
849 pin->SetNumberTextSize( pinTextSize );
850 pin->SetNameTextSize( pinTextSize );
851
852 return pin;
853}
854
855
857{
858 // Convert mm coordinates from KiCad power symbol library to internal units
859 auto mm = [&]( double v ) { return schIUScale.mmToIU( v ); };
860
861 LIB_SYMBOL* sym = new LIB_SYMBOL( wxString::FromUTF8( aKiCadName ) );
862 sym->SetGlobalPower();
863 sym->SetShowPinNumbers( false );
864 sym->SetShowPinNames( false );
865
866 // Determine which visual style to use based on the KiCad symbol name
867 std::string upper = aKiCadName;
868 std::transform( upper.begin(), upper.end(), upper.begin(),
869 []( unsigned char c ) { return std::toupper( c ); } );
870
871 bool isGround = ( upper == "GND" || upper == "GNDA" || upper == "GNDPWR" );
872 bool isGNDD = ( upper == "GNDD" );
873 bool isPwrBar = ( upper == "PWR_BAR" );
874 bool isPwrTriangle = ( upper == "PWR_TRIANGLE" );
875 bool isVEE = ( upper == "VEE" || upper == "VSS" );
876 bool isEarth = ( upper == "EARTH" || upper == "CHASSIS" );
877
878 // Default to VCC style (open arrow up) for anything not matched above
879 bool isVCC = !isGround && !isGNDD && !isPwrBar && !isPwrTriangle
880 && !isVEE && !isEarth;
881
882 if( isGround )
883 {
884 // Standard GND chevron: polyline (0,0)→(0,-1.27)→(1.27,-1.27)→(0,-2.54)→(-1.27,-1.27)→(0,-1.27)
886 shape->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
887 shape->AddPoint( VECTOR2I( mm( 0 ), mm( -1.27 ) ) );
888 shape->AddPoint( VECTOR2I( mm( 1.27 ), mm( -1.27 ) ) );
889 shape->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
890 shape->AddPoint( VECTOR2I( mm( -1.27 ), mm( -1.27 ) ) );
891 shape->AddPoint( VECTOR2I( mm( 0 ), mm( -1.27 ) ) );
893 sym->AddDrawItem( shape );
894
895 SCH_PIN* pin = new SCH_PIN( sym );
896 pin->SetNumber( wxT( "1" ) );
897 pin->SetName( wxString::FromUTF8( aKiCadName ) );
899 pin->SetVisible( false );
900 pin->SetLength( 0 );
901 pin->SetPosition( VECTOR2I( 0, 0 ) );
902 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
903 sym->AddDrawItem( pin );
904 }
905 else if( isGNDD )
906 {
907 // GNDD: thick filled bar + vertical stem
909 bar->SetStart( VECTOR2I( mm( -1.27 ), mm( -1.524 ) ) );
910 bar->SetEnd( VECTOR2I( mm( 1.27 ), mm( -2.032 ) ) );
911 bar->SetStroke( STROKE_PARAMS( mm( 0.254 ), LINE_STYLE::SOLID ) );
913 sym->AddDrawItem( bar );
914
916 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
917 stem->AddPoint( VECTOR2I( mm( 0 ), mm( -1.524 ) ) );
919 sym->AddDrawItem( stem );
920
921 SCH_PIN* pin = new SCH_PIN( sym );
922 pin->SetNumber( wxT( "1" ) );
923 pin->SetName( wxString::FromUTF8( aKiCadName ) );
925 pin->SetVisible( false );
926 pin->SetLength( 0 );
927 pin->SetPosition( VECTOR2I( 0, 0 ) );
928 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
929 sym->AddDrawItem( pin );
930 }
931 else if( isPwrBar )
932 {
933 // PWR_BAR: same bar-down shape as GNDD. Placed with 180° rotation for
934 // positive supplies (+V1) so the bar points up on the schematic.
935 // Negative supplies (-V1) use GNDD directly without rotation.
937 bar->SetStart( VECTOR2I( mm( -1.27 ), mm( -1.524 ) ) );
938 bar->SetEnd( VECTOR2I( mm( 1.27 ), mm( -2.032 ) ) );
939 bar->SetStroke( STROKE_PARAMS( mm( 0.254 ), LINE_STYLE::SOLID ) );
941 sym->AddDrawItem( bar );
942
944 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
945 stem->AddPoint( VECTOR2I( mm( 0 ), mm( -1.524 ) ) );
947 sym->AddDrawItem( stem );
948
949 SCH_PIN* pin = new SCH_PIN( sym );
950 pin->SetNumber( wxT( "1" ) );
951 pin->SetName( wxString::FromUTF8( aKiCadName ) );
953 pin->SetVisible( false );
954 pin->SetLength( 0 );
955 pin->SetPosition( VECTOR2I( 0, 0 ) );
956 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
957 sym->AddDrawItem( pin );
958 }
959 else if( isPwrTriangle )
960 {
961 // PWR_TRIANGLE: filled triangle pointing UP (like -9V style)
963 tri->AddPoint( VECTOR2I( mm( 0.762 ), mm( 1.27 ) ) );
964 tri->AddPoint( VECTOR2I( mm( -0.762 ), mm( 1.27 ) ) );
965 tri->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
966 tri->AddPoint( VECTOR2I( mm( 0.762 ), mm( 1.27 ) ) );
969 sym->AddDrawItem( tri );
970
972 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
973 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 1.27 ) ) );
975 sym->AddDrawItem( stem );
976
977 SCH_PIN* pin = new SCH_PIN( sym );
978 pin->SetNumber( wxT( "1" ) );
979 pin->SetName( wxString::FromUTF8( aKiCadName ) );
981 pin->SetVisible( false );
982 pin->SetLength( 0 );
983 pin->SetPosition( VECTOR2I( 0, 0 ) );
984 pin->SetOrientation( PIN_ORIENTATION::PIN_UP );
985 sym->AddDrawItem( pin );
986 }
987 else if( isVEE )
988 {
989 // VEE: inverted arrow (pointing down), pin at bottom
991 arrow1->AddPoint( VECTOR2I( mm( -0.762 ), mm( -1.27 ) ) );
992 arrow1->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
994 sym->AddDrawItem( arrow1 );
995
997 arrow2->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
998 arrow2->AddPoint( VECTOR2I( mm( 0.762 ), mm( -1.27 ) ) );
1000 sym->AddDrawItem( arrow2 );
1001
1002 SCH_SHAPE* stemLine = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1003 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
1004 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
1005 stemLine->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1006 sym->AddDrawItem( stemLine );
1007
1008 SCH_PIN* pin = new SCH_PIN( sym );
1009 pin->SetNumber( wxT( "1" ) );
1010 pin->SetName( wxString::FromUTF8( aKiCadName ) );
1012 pin->SetVisible( false );
1013 pin->SetLength( 0 );
1014 pin->SetPosition( VECTOR2I( 0, 0 ) );
1015 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
1016 sym->AddDrawItem( pin );
1017 }
1018 else if( isEarth )
1019 {
1020 // Earth: horizontal bars descending in width + vertical stem
1022 bar1->AddPoint( VECTOR2I( mm( -1.27 ), mm( -1.27 ) ) );
1023 bar1->AddPoint( VECTOR2I( mm( 1.27 ), mm( -1.27 ) ) );
1025 sym->AddDrawItem( bar1 );
1026
1028 bar2->AddPoint( VECTOR2I( mm( -0.762 ), mm( -1.778 ) ) );
1029 bar2->AddPoint( VECTOR2I( mm( 0.762 ), mm( -1.778 ) ) );
1031 sym->AddDrawItem( bar2 );
1032
1034 bar3->AddPoint( VECTOR2I( mm( -0.254 ), mm( -2.286 ) ) );
1035 bar3->AddPoint( VECTOR2I( mm( 0.254 ), mm( -2.286 ) ) );
1037 sym->AddDrawItem( bar3 );
1038
1039 SCH_SHAPE* stemLine = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1040 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
1041 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( -1.27 ) ) );
1042 stemLine->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1043 sym->AddDrawItem( stemLine );
1044
1045 SCH_PIN* pin = new SCH_PIN( sym );
1046 pin->SetNumber( wxT( "1" ) );
1047 pin->SetName( wxString::FromUTF8( aKiCadName ) );
1049 pin->SetVisible( false );
1050 pin->SetLength( 0 );
1051 pin->SetPosition( VECTOR2I( 0, 0 ) );
1052 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
1053 sym->AddDrawItem( pin );
1054 }
1055 else if( isVCC )
1056 {
1057 // VCC style: open arrow pointing up + vertical stem
1059 arrow1->AddPoint( VECTOR2I( mm( -0.762 ), mm( 1.27 ) ) );
1060 arrow1->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
1061 arrow1->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1062 sym->AddDrawItem( arrow1 );
1063
1065 arrow2->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
1066 arrow2->AddPoint( VECTOR2I( mm( 0.762 ), mm( 1.27 ) ) );
1067 arrow2->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1068 sym->AddDrawItem( arrow2 );
1069
1070 SCH_SHAPE* stemLine = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1071 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
1072 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
1073 stemLine->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1074 sym->AddDrawItem( stemLine );
1075
1076 SCH_PIN* pin = new SCH_PIN( sym );
1077 pin->SetNumber( wxT( "1" ) );
1078 pin->SetName( wxString::FromUTF8( aKiCadName ) );
1080 pin->SetVisible( false );
1081 pin->SetLength( 0 );
1082 pin->SetPosition( VECTOR2I( 0, 0 ) );
1083 pin->SetOrientation( PIN_ORIENTATION::PIN_UP );
1084 sym->AddDrawItem( pin );
1085 }
1086
1087 sym->GetReferenceField().SetText( wxT( "#PWR" ) );
1088 sym->GetReferenceField().SetVisible( false );
1089
1090 return sym;
1091}
1092
1093
1094std::string PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( const std::string& aDecalName,
1095 const std::string& aPinType )
1096{
1097 std::string upper = aDecalName;
1098 std::transform( upper.begin(), upper.end(), upper.begin(),
1099 []( unsigned char c ) { return std::toupper( c ); } );
1100
1101 bool isPositive = !upper.empty() && upper[0] == '+';
1102 bool isGround = ( aPinType == "G" );
1103
1104 if( upper.find( "RAIL" ) != std::string::npos )
1105 return isPositive ? "PWR_BAR" : "GNDD";
1106
1107 if( upper.find( "ARROW" ) != std::string::npos )
1108 return isPositive ? "PWR_TRIANGLE" : "VEE";
1109
1110 if( upper.find( "BUBBLE" ) != std::string::npos )
1111 return isPositive ? "VCC" : "VEE";
1112
1113 if( isGround )
1114 {
1115 if( upper.find( "CH" ) != std::string::npos )
1116 return "Chassis";
1117
1118 return "GND";
1119 }
1120
1121 if( isPositive )
1122 return "VCC";
1123
1124 return "VEE";
1125}
1126
1127
1129 LIB_SYMBOL* aSymbol, const std::vector<PARTTYPE_DEF::SIGPIN>& aSigpins )
1130{
1131 if( !aSymbol )
1132 return;
1133
1134 // Collect existing pin numbers to avoid duplicates
1135 std::set<wxString> existingPins;
1136
1137 for( const SCH_ITEM& item : aSymbol->GetDrawItems() )
1138 {
1139 if( item.Type() == SCH_PIN_T )
1140 existingPins.insert( static_cast<const SCH_PIN&>( item ).GetNumber() );
1141 }
1142
1143 for( const auto& sp : aSigpins )
1144 {
1145 wxString pinNum = wxString::FromUTF8( sp.pin_number );
1146
1147 if( existingPins.count( pinNum ) )
1148 continue;
1149
1150 SCH_PIN* pin = new SCH_PIN( aSymbol );
1151 pin->SetNumber( pinNum );
1152 pin->SetName( wxString::FromUTF8( sp.net_name ) );
1154 pin->SetVisible( false );
1155 pin->SetLength( 0 );
1156 pin->SetPosition( VECTOR2I( 0, 0 ) );
1157 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
1158
1159 aSymbol->AddDrawItem( pin );
1160 existingPins.insert( pinNum );
1161 }
1162}
1163
1164
1166{
1167 switch( aPadsType )
1168 {
1169 case PIN_TYPE::INPUT: return static_cast<int>( ELECTRICAL_PINTYPE::PT_INPUT );
1170 case PIN_TYPE::OUTPUT: return static_cast<int>( ELECTRICAL_PINTYPE::PT_OUTPUT );
1171 case PIN_TYPE::BIDIRECTIONAL: return static_cast<int>( ELECTRICAL_PINTYPE::PT_BIDI );
1172 case PIN_TYPE::TRISTATE: return static_cast<int>( ELECTRICAL_PINTYPE::PT_TRISTATE );
1173 case PIN_TYPE::OPEN_COLLECTOR: return static_cast<int>( ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR );
1174 case PIN_TYPE::OPEN_EMITTER: return static_cast<int>( ELECTRICAL_PINTYPE::PT_OPENEMITTER );
1175 case PIN_TYPE::POWER: return static_cast<int>( ELECTRICAL_PINTYPE::PT_POWER_IN );
1176 case PIN_TYPE::PASSIVE: return static_cast<int>( ELECTRICAL_PINTYPE::PT_PASSIVE );
1178 default: return static_cast<int>( ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
1179 }
1180}
1181
1182
1183bool PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( const std::string& aName )
1184{
1185 // Convert to uppercase for case-insensitive comparison
1186 std::string upper = aName;
1187 std::transform( upper.begin(), upper.end(), upper.begin(),
1188 []( unsigned char c ) { return std::toupper( c ); } );
1189
1190 // Check for ground variants
1191 if( upper == "GND" || upper == "AGND" || upper == "DGND" || upper == "PGND" ||
1192 upper == "EARTH" || upper == "CHASSIS" || upper == "VSS" || upper == "0V" )
1193 {
1194 return true;
1195 }
1196
1197 // Check for power supply variants
1198 if( upper == "VCC" || upper == "VDD" || upper == "VEE" || upper == "VPP" ||
1199 upper == "VBAT" || upper == "VBUS" || upper == "V+" || upper == "V-" )
1200 {
1201 return true;
1202 }
1203
1204 // Check for voltage patterns like +3V3, +5V, -12V, +V1, -V2, etc.
1205 if( upper.length() >= 2 && ( upper[0] == '+' || upper[0] == '-' ) )
1206 return true;
1207
1208 return false;
1209}
1210
1211
1212std::optional<LIB_ID> PADS_SCH_SYMBOL_BUILDER::GetKiCadPowerSymbolId( const std::string& aPadsName )
1213{
1214 // Convert to uppercase for case-insensitive comparison
1215 std::string upper = aPadsName;
1216 std::transform( upper.begin(), upper.end(), upper.begin(),
1217 []( unsigned char c ) { return std::toupper( c ); } );
1218
1219 // Map common power symbol names to KiCad power library symbols
1220 struct PowerMapping
1221 {
1222 const char* padsName;
1223 const char* kicadSymbol;
1224 };
1225
1226 static const PowerMapping mappings[] = {
1227 { "GND", "GND" },
1228 { "AGND", "GND" },
1229 { "DGND", "GNDD" },
1230 { "PGND", "GNDPWR" },
1231 { "EARTH", "Earth" },
1232 { "CHASSIS", "Chassis" },
1233 { "VSS", "VSS" },
1234 { "0V", "GND" },
1235 { "VCC", "VCC" },
1236 { "VDD", "VDD" },
1237 { "VEE", "VEE" },
1238 { "VPP", "VPP" },
1239 { "VBAT", "VBAT" },
1240 { "VBUS", "VBUS" },
1241 { "V+", "VCC" },
1242 { "V-", "VEE" },
1243 { "+5V", "+5V" },
1244 { "-5V", "-5V" },
1245 { "+3V3", "+3V3" },
1246 { "+3.3V", "+3V3" },
1247 { "+12V", "+12V" },
1248 { "-12V", "-12V" },
1249 { "+15V", "+15V" },
1250 { "-15V", "-15V" },
1251 { "+1V8", "+1V8" },
1252 { "+2V5", "+2V5" },
1253 { "+9V", "+9V" },
1254 { "+24V", "+24V" },
1255 };
1256
1257 for( const auto& mapping : mappings )
1258 {
1259 if( upper == mapping.padsName )
1260 {
1261 LIB_ID libId;
1262 libId.SetLibNickname( "power" );
1263 libId.SetLibItemName( mapping.kicadSymbol );
1264 return libId;
1265 }
1266 }
1267
1268 // Generic fallback for +/- prefixed names not in the table
1269 if( upper.length() >= 2 && upper[0] == '+' )
1270 {
1271 LIB_ID libId;
1272 libId.SetLibNickname( "power" );
1273 libId.SetLibItemName( "VCC" );
1274 return libId;
1275 }
1276
1277 if( upper.length() >= 2 && upper[0] == '-' )
1278 {
1279 LIB_ID libId;
1280 libId.SetLibNickname( "power" );
1281 libId.SetLibItemName( "VEE" );
1282 return libId;
1283 }
1284
1285 return std::nullopt;
1286}
1287
1288} // namespace PADS_SCH
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
void SetCenter(const VECTOR2I &aCenter)
void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:178
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)
void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:546
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:400
void SetTextAngleDegrees(double aOrientation)
Definition eda_text.h:150
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
Define a library symbol object.
Definition lib_symbol.h:83
void SetGlobalPower()
void LockUnits(bool aLockUnits)
Set interchangeable the property for symbol units.
Definition lib_symbol.h:281
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:712
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
void AddDrawItem(SCH_ITEM *aItem, bool aSort=true)
Add a new draw aItem to the draw object list and sort according to aSort.
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
Definition lib_symbol.h:336
static PIN_TYPE ParsePinTypeChar(char aTypeChar)
int mapPinType(PIN_TYPE aPadsType)
Map PADS pin type to KiCad electrical type.
LIB_SYMBOL * BuildMultiUnitSymbol(const PARTTYPE_DEF &aPartType, const std::vector< SYMBOL_DEF > &aSymbolDefs)
Build a composite multi-unit LIB_SYMBOL from a multi-gate PARTTYPE.
bool HasSymbol(const std::string &aName) const
Check if a symbol with the given name already exists.
void AddHiddenPowerPins(LIB_SYMBOL *aSymbol, const std::vector< PARTTYPE_DEF::SIGPIN > &aSigpins)
Add hidden power pins from PARTTYPE SIGPIN entries to an existing symbol.
SCH_PIN * createPin(const SYMBOL_PIN &aPin, LIB_SYMBOL *aParent)
Create a SCH_PIN from a PADS pin definition.
LIB_SYMBOL * GetSymbol(const std::string &aName) const
Get a cached symbol by name.
int toKiCadUnits(double aPadsValue) const
Convert PADS coordinate to KiCad internal units.
LIB_SYMBOL * GetOrCreateMultiUnitSymbol(const PARTTYPE_DEF &aPartType, const std::vector< SYMBOL_DEF > &aSymbolDefs)
Get or create a multi-unit symbol for the given PARTTYPE.
static std::optional< LIB_ID > GetKiCadPowerSymbolId(const std::string &aPadsName)
Get KiCad power library symbol ID for a PADS power symbol.
std::vector< SCH_SHAPE * > createShapes(const SYMBOL_GRAPHIC &aGraphic)
Create one or more SCH_SHAPEs from a PADS graphic element.
LIB_SYMBOL * BuildKiCadPowerSymbol(const std::string &aKiCadName)
Build a power symbol using hard-coded KiCad-standard graphics.
PADS_SCH_SYMBOL_BUILDER(const PARAMETERS &aParams)
static bool IsPowerSymbol(const std::string &aName)
Check if a symbol name indicates a power symbol.
static std::string GetPowerStyleFromVariant(const std::string &aDecalName, const std::string &aPinType)
Map a PADS special_variant to a power symbol style name.
SCH_SHAPE * createShape(const SYMBOL_GRAPHIC &aGraphic)
Create a SCH_SHAPE from a PADS graphic element.
LIB_SYMBOL * GetOrCreateSymbol(const SYMBOL_DEF &aSymbolDef)
Get or create a symbol for the given definition.
LIB_SYMBOL * GetOrCreateConnectorPinSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef, const std::string &aPinNumber)
Get or create a single-pin connector symbol with a specific pin number.
LIB_SYMBOL * GetOrCreateMultiUnitConnectorSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef, const std::vector< std::string > &aPinNumbers, const std::string &aCacheKey)
Get or create a multi-unit connector symbol, cached by base reference.
LIB_SYMBOL * BuildMultiUnitConnectorSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef, const std::vector< std::string > &aPinNumbers)
Build a multi-unit connector symbol where each unit represents one pin.
std::map< std::string, std::unique_ptr< LIB_SYMBOL > > m_symbolCache
LIB_SYMBOL * BuildSymbol(const SYMBOL_DEF &aSymbolDef)
Build a KiCad LIB_SYMBOL from a PADS symbol definition.
LIB_SYMBOL * GetOrCreatePartTypeSymbol(const PARTTYPE_DEF &aPartType, const SYMBOL_DEF &aSymbolDef)
Get or create a single-gate symbol with PARTTYPE-specific pin remapping.
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
virtual void SetUnit(int aUnit)
Definition sch_item.h:238
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_shape.cpp:63
void AddPoint(const VECTOR2I &aPosition)
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
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:58
double m_PadsSchTextWidthScale
PADS text width scale factor for schematic imports.
double m_PadsSchTextHeightScale
PADS text height scale factor for schematic imports.
@ LAYER_DEVICE
Definition layer_ids.h:466
LINE_STYLE PadsLineStyleToKiCad(int aPadsStyle)
Convert a PADS line style integer to a KiCad LINE_STYLE enum value.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
Common utilities and types for parsing PADS file formats.
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_TRISTATE
tri state bus pin
Definition pin_type.h:40
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:39
@ PT_OPENEMITTER
pin type open emitter
Definition pin_type.h:49
@ 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_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
@ 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
GRAPHIC_PINSHAPE
Definition pin_type.h:84
CITER next(CITER it)
Definition ptree.cpp:124
LINE_STYLE
Dashed line types.
Gate definition within a PARTTYPE.
std::vector< std::string > decal_names
std::vector< PARTTYPE_PIN > pins
std::optional< ARC_DATA > arc
General schematic parameters from SCH and FIELDS sections.
Part type definition from PARTTYPE section.
std::vector< GATE_DEF > gates
Symbol definition from CAEDECAL section.
std::vector< SYMBOL_GRAPHIC > graphics
std::vector< SYMBOL_PIN > pins
std::vector< SYMBOL_TEXT > texts
Graphic primitive from CAEDECAL or LINES sections (OPEN, CLOSED, CIRCLE, COPCLS).
std::vector< GRAPHIC_POINT > points
Pin T/P line pair from CAEDECAL.
KIBIS_PIN * pin
VECTOR2I center
int radius
VECTOR2I end
wxString result
Test unit parsing edge cases and error handling.
#define M_PI
@ SCH_PIN_T
Definition typeinfo.h:157
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695