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
17 * along with this program. If not, see <https://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 // PADS Logic ASCII schematics always store geometry in mils. The UNITS field selects only
56 // the design-rules unit and must not scale the schematic coordinates.
57 return schIUScale.MilsToIU( aPadsValue );
58}
59
60
62{
63 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aSymbolDef.name ) );
64
65 // Add graphics
66 for( const auto& graphic : aSymbolDef.graphics )
67 {
68 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
69
70 for( SCH_SHAPE* shape : shapes )
71 libSymbol->AddDrawItem( shape );
72 }
73
74 // Add pins
75 for( const auto& pin : aSymbolDef.pins )
76 {
77 SCH_PIN* schPin = createPin( pin, libSymbol );
78
79 if( schPin )
80 libSymbol->AddDrawItem( schPin );
81 }
82
83 // Add embedded text labels
84 for( const auto& text : aSymbolDef.texts )
85 {
86 if( text.content.empty() )
87 continue;
88
89 SCH_TEXT* schText = new SCH_TEXT(
90 VECTOR2I( toKiCadUnits( text.position.x ), -toKiCadUnits( text.position.y ) ),
91 wxString::FromUTF8( text.content ), LAYER_DEVICE );
92
93 if( text.size > 0.0 )
94 {
95 int scaledSize = toKiCadUnits( text.size );
96 int charHeight = static_cast<int>(
98 int charWidth = static_cast<int>(
100 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
101 }
102
103 if( text.rotation != 0.0 )
104 schText->SetTextAngleDegrees( text.rotation );
105
106 libSymbol->AddDrawItem( schText );
107 }
108
109 libSymbol->SetShowPinNumbers( false );
110 libSymbol->SetShowPinNames( false );
111
112 return libSymbol;
113}
114
115
117{
118 auto it = m_symbolCache.find( aSymbolDef.name );
119
120 if( it != m_symbolCache.end() )
121 return it->second.get();
122
123 LIB_SYMBOL* newSymbol = BuildSymbol( aSymbolDef );
124 m_symbolCache[aSymbolDef.name] = std::unique_ptr<LIB_SYMBOL>( newSymbol );
125
126 return newSymbol;
127}
128
129
131 const PARTTYPE_DEF& aPartType, const std::vector<SYMBOL_DEF>& aSymbolDefs )
132{
133 // Build a lookup from CAEDECAL name to definition
134 std::map<std::string, const SYMBOL_DEF*> symDefByName;
135
136 for( const auto& sd : aSymbolDefs )
137 symDefByName[sd.name] = &sd;
138
139 int gateCount = static_cast<int>( aPartType.gates.size() );
140 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aPartType.name ) );
141 libSymbol->SetUnitCount( gateCount, false );
142 libSymbol->LockUnits( true );
143
144 for( int gi = 0; gi < gateCount; gi++ )
145 {
146 const GATE_DEF& gate = aPartType.gates[gi];
147 int unit = gi + 1;
148
149 // Resolve the CAEDECAL for this gate
150 std::string decalName;
151
152 if( !gate.decal_names.empty() )
153 decalName = gate.decal_names[0];
154
155 auto sdIt = symDefByName.find( decalName );
156
157 if( sdIt == symDefByName.end() )
158 continue;
159
160 const SYMBOL_DEF& symDef = *sdIt->second;
161
162 // Add graphics for this unit
163 for( const auto& graphic : symDef.graphics )
164 {
165 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
166
167 for( SCH_SHAPE* shape : shapes )
168 {
169 shape->SetUnit( unit );
170 libSymbol->AddDrawItem( shape );
171 }
172 }
173
174 // Add pins with PARTTYPE overrides
175 for( size_t p = 0; p < symDef.pins.size(); p++ )
176 {
177 SYMBOL_PIN pin = symDef.pins[p];
178
179 if( p < gate.pins.size() )
180 {
181 pin.name = gate.pins[p].pin_name;
182 pin.number = gate.pins[p].pin_id;
183
184 if( gate.pins[p].pin_type != 0 )
185 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( gate.pins[p].pin_type );
186 }
187
188 SCH_PIN* schPin = createPin( pin, libSymbol );
189
190 if( schPin )
191 {
192 schPin->SetUnit( unit );
193 libSymbol->AddDrawItem( schPin );
194 }
195 }
196
197 // Add embedded text labels for this unit
198 for( const auto& text : symDef.texts )
199 {
200 if( text.content.empty() )
201 continue;
202
203 SCH_TEXT* schText = new SCH_TEXT(
204 VECTOR2I( toKiCadUnits( text.position.x ),
205 -toKiCadUnits( text.position.y ) ),
206 wxString::FromUTF8( text.content ), LAYER_DEVICE );
207
208 if( text.size > 0.0 )
209 {
210 int scaledSize = toKiCadUnits( text.size );
211 int charHeight = static_cast<int>(
213 int charWidth = static_cast<int>(
215 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
216 }
217
218 if( text.rotation != 0.0 )
219 schText->SetTextAngleDegrees( text.rotation );
220
221 schText->SetUnit( unit );
222 libSymbol->AddDrawItem( schText );
223 }
224 }
225
226 libSymbol->SetShowPinNumbers( true );
227 libSymbol->SetShowPinNames( true );
228
229 return libSymbol;
230}
231
232
234 const PARTTYPE_DEF& aPartType, const std::vector<SYMBOL_DEF>& aSymbolDefs )
235{
236 // Use a prefixed key to avoid collision with CAEDECAL symbols that may
237 // share the same name as the PARTTYPE (e.g. both named "TL082").
238 std::string cacheKey = "parttype:" + aPartType.name;
239 auto it = m_symbolCache.find( cacheKey );
240
241 if( it != m_symbolCache.end() )
242 return it->second.get();
243
244 LIB_SYMBOL* newSymbol = BuildMultiUnitSymbol( aPartType, aSymbolDefs );
245 m_symbolCache[cacheKey] = std::unique_ptr<LIB_SYMBOL>( newSymbol );
246
247 return newSymbol;
248}
249
250
252 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef )
253{
254 // Cache by PARTTYPE + CAEDECAL pair. A single-gate PARTTYPE with multiple decal
255 // variants (e.g. horizontal vs vertical resistor) needs a separate LIB_SYMBOL per
256 // variant because the graphics and pin positions differ.
257 std::string cacheKey = aPartType.name + ":" + aSymbolDef.name;
258 auto it = m_symbolCache.find( cacheKey );
259
260 if( it != m_symbolCache.end() )
261 return it->second.get();
262
263 if( aPartType.gates.empty() )
264 return nullptr;
265
266 // Build from the CAEDECAL then apply pin overrides from the PARTTYPE gate
267 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aSymbolDef.name ) );
268
269 for( const auto& graphic : aSymbolDef.graphics )
270 {
271 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
272
273 for( SCH_SHAPE* shape : shapes )
274 libSymbol->AddDrawItem( shape );
275 }
276
277 const GATE_DEF& gate = aPartType.gates[0];
278
279 for( size_t p = 0; p < aSymbolDef.pins.size(); p++ )
280 {
281 SYMBOL_PIN pin = aSymbolDef.pins[p];
282
283 if( p < gate.pins.size() )
284 {
285 pin.name = gate.pins[p].pin_name;
286 pin.number = gate.pins[p].pin_id;
287
288 if( gate.pins[p].pin_type != 0 )
289 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( gate.pins[p].pin_type );
290 }
291
292 SCH_PIN* schPin = createPin( pin, libSymbol );
293
294 if( schPin )
295 libSymbol->AddDrawItem( schPin );
296 }
297
298 for( const auto& text : aSymbolDef.texts )
299 {
300 if( text.content.empty() )
301 continue;
302
303 SCH_TEXT* schText = new SCH_TEXT(
304 VECTOR2I( toKiCadUnits( text.position.x ),
305 -toKiCadUnits( text.position.y ) ),
306 wxString::FromUTF8( text.content ), LAYER_DEVICE );
307
308 if( text.size > 0.0 )
309 {
310 int scaledSize = toKiCadUnits( text.size );
311 int charHeight = static_cast<int>(
313 int charWidth = static_cast<int>(
315 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
316 }
317
318 if( text.rotation != 0.0 )
319 schText->SetTextAngleDegrees( text.rotation );
320
321 libSymbol->AddDrawItem( schText );
322 }
323
324 // Show pin names/numbers if any gate pin has an explicit name
325 bool hasPinNames = false;
326
327 for( const auto& pin : gate.pins )
328 {
329 if( !pin.pin_name.empty() )
330 {
331 hasPinNames = true;
332 break;
333 }
334 }
335
336 // Connectors number their pins even though they carry no pin names. A single
337 // multi-pin connector placement (no per-pin reference suffix) still routes here,
338 // so force pin numbers on for connector part types.
339 libSymbol->SetShowPinNumbers( hasPinNames || aPartType.is_connector );
340 libSymbol->SetShowPinNames( hasPinNames );
341
342 m_symbolCache[cacheKey] = std::unique_ptr<LIB_SYMBOL>( libSymbol );
343
344 return libSymbol;
345}
346
347
349 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef,
350 const std::string& aPinNumber )
351{
352 std::string cacheKey = aPartType.name + ":" + aSymbolDef.name + ":" + aPinNumber;
353 auto it = m_symbolCache.find( cacheKey );
354
355 if( it != m_symbolCache.end() )
356 return it->second.get();
357
358 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aSymbolDef.name ) );
359
360 for( const auto& graphic : aSymbolDef.graphics )
361 {
362 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
363
364 for( SCH_SHAPE* shape : shapes )
365 libSymbol->AddDrawItem( shape );
366 }
367
368 // Create pin(s) from the CAEDECAL but override the pin number
369 for( size_t p = 0; p < aSymbolDef.pins.size(); p++ )
370 {
371 SYMBOL_PIN pin = aSymbolDef.pins[p];
372 pin.number = aPinNumber;
373
374 if( !aPartType.gates.empty() && p < aPartType.gates[0].pins.size() )
375 {
376 pin.name = aPartType.gates[0].pins[p].pin_name;
377
378 if( aPartType.gates[0].pins[p].pin_type != 0 )
379 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( aPartType.gates[0].pins[p].pin_type );
380 }
381
382 SCH_PIN* schPin = createPin( pin, libSymbol );
383
384 if( schPin )
385 libSymbol->AddDrawItem( schPin );
386 }
387
388 for( const auto& text : aSymbolDef.texts )
389 {
390 if( text.content.empty() )
391 continue;
392
393 SCH_TEXT* schText = new SCH_TEXT(
394 VECTOR2I( toKiCadUnits( text.position.x ),
395 -toKiCadUnits( text.position.y ) ),
396 wxString::FromUTF8( text.content ), LAYER_DEVICE );
397
398 if( text.size > 0.0 )
399 {
400 int scaledSize = toKiCadUnits( text.size );
401 int charHeight = static_cast<int>(
403 int charWidth = static_cast<int>(
405 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
406 }
407
408 if( text.rotation != 0.0 )
409 schText->SetTextAngleDegrees( text.rotation );
410
411 libSymbol->AddDrawItem( schText );
412 }
413
414 libSymbol->SetShowPinNumbers( false );
415 libSymbol->SetShowPinNames( false );
416
417 m_symbolCache[cacheKey] = std::unique_ptr<LIB_SYMBOL>( libSymbol );
418
419 return libSymbol;
420}
421
422
424 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef,
425 const std::vector<std::string>& aPinNumbers )
426{
427 int unitCount = static_cast<int>( aPinNumbers.size() );
428 LIB_SYMBOL* libSymbol = new LIB_SYMBOL( wxString::FromUTF8( aPartType.name ) );
429 libSymbol->SetUnitCount( unitCount, false );
430 libSymbol->LockUnits( true );
431
432 // Build a lookup from pin ID to PARTTYPE pin definition
433 std::map<std::string, const PARTTYPE_PIN*> ptPinById;
434
435 if( !aPartType.gates.empty() )
436 {
437 for( const auto& ptPin : aPartType.gates[0].pins )
438 ptPinById[ptPin.pin_id] = &ptPin;
439 }
440
441 for( int u = 0; u < unitCount; u++ )
442 {
443 int unit = u + 1;
444
445 for( const auto& graphic : aSymbolDef.graphics )
446 {
447 std::vector<SCH_SHAPE*> shapes = createShapes( graphic );
448
449 for( SCH_SHAPE* shape : shapes )
450 {
451 shape->SetUnit( unit );
452 libSymbol->AddDrawItem( shape );
453 }
454 }
455
456 // One pin per unit with the correct pin number
457 if( !aSymbolDef.pins.empty() )
458 {
459 SYMBOL_PIN pin = aSymbolDef.pins[0];
460 pin.number = aPinNumbers[u];
461
462 auto ptPinIt = ptPinById.find( aPinNumbers[u] );
463
464 if( ptPinIt != ptPinById.end() )
465 {
466 if( ptPinIt->second->pin_type != 0 )
467 pin.type = PADS_SCH_PARSER::ParsePinTypeChar( ptPinIt->second->pin_type );
468
469 if( !ptPinIt->second->pin_name.empty() )
470 pin.name = ptPinIt->second->pin_name;
471 }
472
473 SCH_PIN* schPin = createPin( pin, libSymbol );
474
475 if( schPin )
476 {
477 schPin->SetUnit( unit );
478 libSymbol->AddDrawItem( schPin );
479 }
480 }
481
482 for( const auto& text : aSymbolDef.texts )
483 {
484 if( text.content.empty() )
485 continue;
486
487 SCH_TEXT* schText = new SCH_TEXT(
488 VECTOR2I( toKiCadUnits( text.position.x ),
489 -toKiCadUnits( text.position.y ) ),
490 wxString::FromUTF8( text.content ), LAYER_DEVICE );
491
492 if( text.size > 0.0 )
493 {
494 int scaledSize = toKiCadUnits( text.size );
495 int charHeight = static_cast<int>(
497 int charWidth = static_cast<int>(
499 schText->SetTextSize( VECTOR2I( charWidth, charHeight ) );
500 }
501
502 if( text.rotation != 0.0 )
503 schText->SetTextAngleDegrees( text.rotation );
504
505 schText->SetUnit( unit );
506 libSymbol->AddDrawItem( schText );
507 }
508 }
509
510 libSymbol->SetShowPinNumbers( true );
511 libSymbol->SetShowPinNames( false );
512
513 return libSymbol;
514}
515
516
518 const PARTTYPE_DEF& aPartType, const SYMBOL_DEF& aSymbolDef,
519 const std::vector<std::string>& aPinNumbers, const std::string& aCacheKey )
520{
521 auto it = m_symbolCache.find( aCacheKey );
522
523 if( it != m_symbolCache.end() )
524 return it->second.get();
525
526 LIB_SYMBOL* newSymbol = BuildMultiUnitConnectorSymbol( aPartType, aSymbolDef, aPinNumbers );
527 m_symbolCache[aCacheKey] = std::unique_ptr<LIB_SYMBOL>( newSymbol );
528
529 return newSymbol;
530}
531
532
533bool PADS_SCH_SYMBOL_BUILDER::HasSymbol( const std::string& aName ) const
534{
535 return m_symbolCache.find( aName ) != m_symbolCache.end();
536}
537
538
539LIB_SYMBOL* PADS_SCH_SYMBOL_BUILDER::GetSymbol( const std::string& aName ) const
540{
541 auto it = m_symbolCache.find( aName );
542
543 if( it != m_symbolCache.end() )
544 return it->second.get();
545
546 return nullptr;
547}
548
549
551{
552 SCH_SHAPE* shape = nullptr;
553
554 switch( aGraphic.type )
555 {
558 {
559 bool hasArcs = false;
560
561 for( const auto& pt : aGraphic.points )
562 {
563 if( pt.arc.has_value() )
564 {
565 hasArcs = true;
566 break;
567 }
568 }
569
570 if( !hasArcs )
571 {
572 shape = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
573
574 for( const auto& pt : aGraphic.points )
575 shape->AddPoint( VECTOR2I( toKiCadUnits( pt.coord.x ),
576 -toKiCadUnits( pt.coord.y ) ) );
577 }
578 else
579 {
580 // Mixed line/arc path requires multiple shapes. Return nullptr here and let
581 // BuildSymbol handle this via createShapes() instead.
582 return nullptr;
583 }
584
585 break;
586 }
587
589 {
591
592 if( aGraphic.points.size() >= 2 )
593 {
594 VECTOR2I start( toKiCadUnits( aGraphic.points[0].coord.x ),
595 -toKiCadUnits( aGraphic.points[0].coord.y ) );
596 VECTOR2I end( toKiCadUnits( aGraphic.points[1].coord.x ),
597 -toKiCadUnits( aGraphic.points[1].coord.y ) );
598
599 shape->SetStart( start );
600 shape->SetEnd( end );
601 }
602
603 break;
604 }
605
607 {
608 shape = new SCH_SHAPE( SHAPE_T::CIRCLE, LAYER_DEVICE );
609
610 VECTOR2I center( toKiCadUnits( aGraphic.center.x ), -toKiCadUnits( aGraphic.center.y ) );
611 int radius = toKiCadUnits( aGraphic.radius );
612
613 shape->SetStart( center );
614 shape->SetEnd( VECTOR2I( center.x + radius, center.y ) );
615
616 break;
617 }
618
620 {
621 shape = new SCH_SHAPE( SHAPE_T::ARC, LAYER_DEVICE );
622
623 VECTOR2I center( toKiCadUnits( aGraphic.center.x ), -toKiCadUnits( aGraphic.center.y ) );
624 int radius = toKiCadUnits( aGraphic.radius );
625
626 // Convert angles from PADS format to KiCad
627 // PADS uses degrees, KiCad uses tenths of degrees for arc definition
628 double startAngle = aGraphic.start_angle * M_PI / 180.0;
629 double endAngle = aGraphic.end_angle * M_PI / 180.0;
630
631 VECTOR2I startPt( center.x + radius * cos( startAngle ),
632 center.y - radius * sin( startAngle ) );
633 VECTOR2I endPt( center.x + radius * cos( endAngle ),
634 center.y - radius * sin( endAngle ) );
635
636 shape->SetStart( startPt );
637 shape->SetEnd( endPt );
638 shape->SetCenter( center );
639
640 break;
641 }
642 }
643
644 if( shape )
645 {
646 int lineWidth = toKiCadUnits( aGraphic.line_width );
647
648 if( lineWidth == 0 )
649 lineWidth = toKiCadUnits( m_params.line_width );
650
651 shape->SetStroke( STROKE_PARAMS( lineWidth, PADS_COMMON::PadsLineStyleToKiCad( aGraphic.line_style ) ) );
652
653 if( aGraphic.filled )
655 }
656
657 return shape;
658}
659
660
661std::vector<SCH_SHAPE*> PADS_SCH_SYMBOL_BUILDER::createShapes( const SYMBOL_GRAPHIC& aGraphic )
662{
663 std::vector<SCH_SHAPE*> result;
664
665 // Try the simple single-shape path first
666 SCH_SHAPE* single = createShape( aGraphic );
667
668 if( single )
669 {
670 result.push_back( single );
671 return result;
672 }
673
674 // Mixed line/arc path: emit individual segments
675 int lineWidth = toKiCadUnits( aGraphic.line_width );
676
677 if( lineWidth == 0 )
678 lineWidth = toKiCadUnits( m_params.line_width );
679
681
682 for( size_t i = 0; i + 1 < aGraphic.points.size(); i++ )
683 {
684 const GRAPHIC_POINT& cur = aGraphic.points[i];
685 const GRAPHIC_POINT& next = aGraphic.points[i + 1];
686
687 VECTOR2I startPt( toKiCadUnits( cur.coord.x ), -toKiCadUnits( cur.coord.y ) );
688 VECTOR2I endPt( toKiCadUnits( next.coord.x ), -toKiCadUnits( next.coord.y ) );
689
690 if( cur.arc.has_value() )
691 {
692 const ARC_DATA& ad = *cur.arc;
693 double cx = ( ad.bbox_x1 + ad.bbox_x2 ) / 2.0;
694 double cy = ( ad.bbox_y1 + ad.bbox_y2 ) / 2.0;
695 VECTOR2I center( toKiCadUnits( cx ), -toKiCadUnits( cy ) );
696
697 // Compute the arc midpoint on the circle between start and end.
698 // Use vector math: midpoint of arc = center + R * normalize(midvector)
699 // where midvector = (start - center) + (end - center)
700 double sx = startPt.x - center.x;
701 double sy = startPt.y - center.y;
702 double ex = endPt.x - center.x;
703 double ey = endPt.y - center.y;
704 double radius = std::sqrt( sx * sx + sy * sy );
705
706 double mx = sx + ex;
707 double my = sy + ey;
708 double mlen = std::sqrt( mx * mx + my * my );
709
710 VECTOR2I midPt;
711
712 if( mlen > 0.001 )
713 {
714 midPt.x = center.x + static_cast<int>( radius * mx / mlen );
715 midPt.y = center.y + static_cast<int>( radius * my / mlen );
716 }
717 else
718 {
719 // Start and end are diametrically opposite, pick perpendicular direction
720 midPt.x = center.x + static_cast<int>( -sy * radius / std::max( radius, 1.0 ) );
721 midPt.y = center.y + static_cast<int>( sx * radius / std::max( radius, 1.0 ) );
722 }
723
724 // The initial midpoint is always on the minor arc side (between start
725 // and end radii). Flip to the major arc side when the sweep exceeds
726 // 180 degrees. The sign of the angle encodes CW/CCW direction in PADS
727 // but does not affect which semicircle the arc occupies.
728 if( std::abs( ad.angle ) > 1800 )
729 {
730 midPt.x = 2 * center.x - midPt.x;
731 midPt.y = 2 * center.y - midPt.y;
732 }
733
735 arc->SetArcGeometry( startPt, midPt, endPt );
736 arc->SetStroke( STROKE_PARAMS( lineWidth, lineStyle ) );
737
738 if( aGraphic.filled )
740
741 result.push_back( arc );
742 }
743 else
744 {
745 if( startPt == endPt )
746 continue;
747
749 line->AddPoint( startPt );
750 line->AddPoint( endPt );
751 line->SetStroke( STROKE_PARAMS( lineWidth, lineStyle ) );
752
753 if( aGraphic.filled )
755
756 result.push_back( line );
757 }
758 }
759
760 return result;
761}
762
763
765{
766 SCH_PIN* pin = new SCH_PIN( aParent );
767
768 // Set pin name and number
769 pin->SetName( wxString::FromUTF8( aPin.name ) );
770 pin->SetNumber( wxString::FromUTF8( aPin.number ) );
771
772 // Set pin position (end point where wire connects)
773 VECTOR2I pos( toKiCadUnits( aPin.position.x ), -toKiCadUnits( aPin.position.y ) );
774 pin->SetPosition( pos );
775
776 // Set pin length
777 int length = toKiCadUnits( aPin.length );
778 pin->SetLength( length );
779
780 // Determine pin orientation from the T-line angle and side fields.
781 // The angle indicates pin text rotation (0=horizontal, 90=vertical) while
782 // the side field indicates which edge of the symbol body the pin is on.
783 // Pin decal names containing "VRT" indicate perpendicular pins.
785 bool isVerticalDecal = ( aPin.pin_decal_name.find( "VRT" ) != std::string::npos );
786 int angle = static_cast<int>( aPin.rotation ) % 360;
787
788 if( isVerticalDecal )
789 {
790 orientation = ( aPin.side == 2 ) ? PIN_ORIENTATION::PIN_UP
792 }
793 else if( angle >= 45 && angle < 135 )
794 {
795 // Sides 0,1 (horizontal edges) point up; sides 2,3 (vertical edges) point down
796 orientation = ( aPin.side >= 2 ) ? PIN_ORIENTATION::PIN_DOWN
798 }
799 else if( angle >= 225 && angle < 315 )
800 {
801 orientation = ( aPin.side >= 2 ) ? PIN_ORIENTATION::PIN_UP
803 }
804 else if( angle >= 135 && angle < 225 )
805 {
806 orientation = ( aPin.side & 1 ) ? PIN_ORIENTATION::PIN_RIGHT
808 }
809 else
810 {
811 orientation = ( aPin.side & 1 ) ? PIN_ORIENTATION::PIN_LEFT
813 }
814
815 pin->SetOrientation( orientation );
816
817 // Set electrical type
818 ELECTRICAL_PINTYPE pinType = static_cast<ELECTRICAL_PINTYPE>( mapPinType( aPin.type ) );
819 pin->SetType( pinType );
820
821 // Set graphic style
823
824 if( aPin.inverted )
826 else if( aPin.clock )
827 pinShape = GRAPHIC_PINSHAPE::CLOCK;
828
829 pin->SetShape( pinShape );
830
831 int pinTextSize = schIUScale.MilsToIU( 50 );
832 pin->SetNumberTextSize( pinTextSize );
833 pin->SetNameTextSize( pinTextSize );
834
835 return pin;
836}
837
838
840{
841 // Convert mm coordinates from KiCad power symbol library to internal units
842 auto mm = [&]( double v ) { return schIUScale.mmToIU( v ); };
843
844 LIB_SYMBOL* sym = new LIB_SYMBOL( wxString::FromUTF8( aKiCadName ) );
845 sym->SetGlobalPower();
846 sym->SetShowPinNumbers( false );
847 sym->SetShowPinNames( false );
848
849 // Determine which visual style to use based on the KiCad symbol name
850 std::string upper = aKiCadName;
851 std::transform( upper.begin(), upper.end(), upper.begin(),
852 []( unsigned char c ) { return std::toupper( c ); } );
853
854 bool isGround = ( upper == "GND" || upper == "GNDA" || upper == "GNDPWR" );
855 bool isGNDD = ( upper == "GNDD" );
856 bool isPwrBar = ( upper == "PWR_BAR" );
857 bool isPwrTriangle = ( upper == "PWR_TRIANGLE" );
858 bool isVEE = ( upper == "VEE" || upper == "VSS" );
859 bool isEarth = ( upper == "EARTH" || upper == "CHASSIS" );
860
861 // Default to VCC style (open arrow up) for anything not matched above
862 bool isVCC = !isGround && !isGNDD && !isPwrBar && !isPwrTriangle
863 && !isVEE && !isEarth;
864
865 if( isGround )
866 {
867 // Standard GND chevron: polyline (0,0)→(0,-1.27)→(1.27,-1.27)→(0,-2.54)→(-1.27,-1.27)→(0,-1.27)
869 shape->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
870 shape->AddPoint( VECTOR2I( mm( 0 ), mm( -1.27 ) ) );
871 shape->AddPoint( VECTOR2I( mm( 1.27 ), mm( -1.27 ) ) );
872 shape->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
873 shape->AddPoint( VECTOR2I( mm( -1.27 ), mm( -1.27 ) ) );
874 shape->AddPoint( VECTOR2I( mm( 0 ), mm( -1.27 ) ) );
876 sym->AddDrawItem( shape );
877
878 SCH_PIN* pin = new SCH_PIN( sym );
879 pin->SetNumber( wxT( "1" ) );
880 pin->SetName( wxString::FromUTF8( aKiCadName ) );
882 pin->SetVisible( false );
883 pin->SetLength( 0 );
884 pin->SetPosition( VECTOR2I( 0, 0 ) );
885 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
886 sym->AddDrawItem( pin );
887 }
888 else if( isGNDD )
889 {
890 // GNDD: thick filled bar + vertical stem
892 bar->SetStart( VECTOR2I( mm( -1.27 ), mm( -1.524 ) ) );
893 bar->SetEnd( VECTOR2I( mm( 1.27 ), mm( -2.032 ) ) );
894 bar->SetStroke( STROKE_PARAMS( mm( 0.254 ), LINE_STYLE::SOLID ) );
896 sym->AddDrawItem( bar );
897
899 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
900 stem->AddPoint( VECTOR2I( mm( 0 ), mm( -1.524 ) ) );
902 sym->AddDrawItem( stem );
903
904 SCH_PIN* pin = new SCH_PIN( sym );
905 pin->SetNumber( wxT( "1" ) );
906 pin->SetName( wxString::FromUTF8( aKiCadName ) );
908 pin->SetVisible( false );
909 pin->SetLength( 0 );
910 pin->SetPosition( VECTOR2I( 0, 0 ) );
911 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
912 sym->AddDrawItem( pin );
913 }
914 else if( isPwrBar )
915 {
916 // PWR_BAR: same bar-down shape as GNDD. Placed with 180° rotation for
917 // positive supplies (+V1) so the bar points up on the schematic.
918 // Negative supplies (-V1) use GNDD directly without rotation.
920 bar->SetStart( VECTOR2I( mm( -1.27 ), mm( -1.524 ) ) );
921 bar->SetEnd( VECTOR2I( mm( 1.27 ), mm( -2.032 ) ) );
922 bar->SetStroke( STROKE_PARAMS( mm( 0.254 ), LINE_STYLE::SOLID ) );
924 sym->AddDrawItem( bar );
925
927 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
928 stem->AddPoint( VECTOR2I( mm( 0 ), mm( -1.524 ) ) );
930 sym->AddDrawItem( stem );
931
932 SCH_PIN* pin = new SCH_PIN( sym );
933 pin->SetNumber( wxT( "1" ) );
934 pin->SetName( wxString::FromUTF8( aKiCadName ) );
936 pin->SetVisible( false );
937 pin->SetLength( 0 );
938 pin->SetPosition( VECTOR2I( 0, 0 ) );
939 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
940 sym->AddDrawItem( pin );
941 }
942 else if( isPwrTriangle )
943 {
944 // PWR_TRIANGLE: filled triangle pointing UP (like -9V style)
946 tri->AddPoint( VECTOR2I( mm( 0.762 ), mm( 1.27 ) ) );
947 tri->AddPoint( VECTOR2I( mm( -0.762 ), mm( 1.27 ) ) );
948 tri->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
949 tri->AddPoint( VECTOR2I( mm( 0.762 ), mm( 1.27 ) ) );
952 sym->AddDrawItem( tri );
953
955 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
956 stem->AddPoint( VECTOR2I( mm( 0 ), mm( 1.27 ) ) );
958 sym->AddDrawItem( stem );
959
960 SCH_PIN* pin = new SCH_PIN( sym );
961 pin->SetNumber( wxT( "1" ) );
962 pin->SetName( wxString::FromUTF8( aKiCadName ) );
964 pin->SetVisible( false );
965 pin->SetLength( 0 );
966 pin->SetPosition( VECTOR2I( 0, 0 ) );
967 pin->SetOrientation( PIN_ORIENTATION::PIN_UP );
968 sym->AddDrawItem( pin );
969 }
970 else if( isVEE )
971 {
972 // VEE: inverted arrow (pointing down), pin at bottom
974 arrow1->AddPoint( VECTOR2I( mm( -0.762 ), mm( -1.27 ) ) );
975 arrow1->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
977 sym->AddDrawItem( arrow1 );
978
980 arrow2->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
981 arrow2->AddPoint( VECTOR2I( mm( 0.762 ), mm( -1.27 ) ) );
983 sym->AddDrawItem( arrow2 );
984
985 SCH_SHAPE* stemLine = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
986 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
987 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( -2.54 ) ) );
988 stemLine->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
989 sym->AddDrawItem( stemLine );
990
991 SCH_PIN* pin = new SCH_PIN( sym );
992 pin->SetNumber( wxT( "1" ) );
993 pin->SetName( wxString::FromUTF8( aKiCadName ) );
995 pin->SetVisible( false );
996 pin->SetLength( 0 );
997 pin->SetPosition( VECTOR2I( 0, 0 ) );
998 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
999 sym->AddDrawItem( pin );
1000 }
1001 else if( isEarth )
1002 {
1003 // Earth: horizontal bars descending in width + vertical stem
1005 bar1->AddPoint( VECTOR2I( mm( -1.27 ), mm( -1.27 ) ) );
1006 bar1->AddPoint( VECTOR2I( mm( 1.27 ), mm( -1.27 ) ) );
1008 sym->AddDrawItem( bar1 );
1009
1011 bar2->AddPoint( VECTOR2I( mm( -0.762 ), mm( -1.778 ) ) );
1012 bar2->AddPoint( VECTOR2I( mm( 0.762 ), mm( -1.778 ) ) );
1014 sym->AddDrawItem( bar2 );
1015
1017 bar3->AddPoint( VECTOR2I( mm( -0.254 ), mm( -2.286 ) ) );
1018 bar3->AddPoint( VECTOR2I( mm( 0.254 ), mm( -2.286 ) ) );
1020 sym->AddDrawItem( bar3 );
1021
1022 SCH_SHAPE* stemLine = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1023 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
1024 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( -1.27 ) ) );
1025 stemLine->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1026 sym->AddDrawItem( stemLine );
1027
1028 SCH_PIN* pin = new SCH_PIN( sym );
1029 pin->SetNumber( wxT( "1" ) );
1030 pin->SetName( wxString::FromUTF8( aKiCadName ) );
1032 pin->SetVisible( false );
1033 pin->SetLength( 0 );
1034 pin->SetPosition( VECTOR2I( 0, 0 ) );
1035 pin->SetOrientation( PIN_ORIENTATION::PIN_DOWN );
1036 sym->AddDrawItem( pin );
1037 }
1038 else if( isVCC )
1039 {
1040 // VCC style: open arrow pointing up + vertical stem
1042 arrow1->AddPoint( VECTOR2I( mm( -0.762 ), mm( 1.27 ) ) );
1043 arrow1->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
1044 arrow1->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1045 sym->AddDrawItem( arrow1 );
1046
1048 arrow2->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
1049 arrow2->AddPoint( VECTOR2I( mm( 0.762 ), mm( 1.27 ) ) );
1050 arrow2->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1051 sym->AddDrawItem( arrow2 );
1052
1053 SCH_SHAPE* stemLine = new SCH_SHAPE( SHAPE_T::POLY, LAYER_DEVICE );
1054 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 0 ) ) );
1055 stemLine->AddPoint( VECTOR2I( mm( 0 ), mm( 2.54 ) ) );
1056 stemLine->SetStroke( STROKE_PARAMS( 0, LINE_STYLE::SOLID ) );
1057 sym->AddDrawItem( stemLine );
1058
1059 SCH_PIN* pin = new SCH_PIN( sym );
1060 pin->SetNumber( wxT( "1" ) );
1061 pin->SetName( wxString::FromUTF8( aKiCadName ) );
1063 pin->SetVisible( false );
1064 pin->SetLength( 0 );
1065 pin->SetPosition( VECTOR2I( 0, 0 ) );
1066 pin->SetOrientation( PIN_ORIENTATION::PIN_UP );
1067 sym->AddDrawItem( pin );
1068 }
1069
1070 sym->GetReferenceField().SetText( wxT( "#PWR" ) );
1071 sym->GetReferenceField().SetVisible( false );
1072
1073 return sym;
1074}
1075
1076
1077std::string PADS_SCH_SYMBOL_BUILDER::GetPowerStyleFromVariant( const std::string& aDecalName,
1078 const std::string& aPinType )
1079{
1080 std::string upper = aDecalName;
1081 std::transform( upper.begin(), upper.end(), upper.begin(),
1082 []( unsigned char c ) { return std::toupper( c ); } );
1083
1084 bool isPositive = !upper.empty() && upper[0] == '+';
1085 bool isGround = ( aPinType == "G" );
1086
1087 if( upper.find( "RAIL" ) != std::string::npos )
1088 return isPositive ? "PWR_BAR" : "GNDD";
1089
1090 if( upper.find( "ARROW" ) != std::string::npos )
1091 return isPositive ? "PWR_TRIANGLE" : "VEE";
1092
1093 if( upper.find( "BUBBLE" ) != std::string::npos )
1094 return isPositive ? "VCC" : "VEE";
1095
1096 if( isGround )
1097 {
1098 if( upper.find( "CH" ) != std::string::npos )
1099 return "Chassis";
1100
1101 return "GND";
1102 }
1103
1104 if( isPositive )
1105 return "VCC";
1106
1107 return "VEE";
1108}
1109
1110
1112 LIB_SYMBOL* aSymbol, const std::vector<PARTTYPE_DEF::SIGPIN>& aSigpins )
1113{
1114 if( !aSymbol )
1115 return;
1116
1117 // Collect existing pin numbers to avoid duplicates
1118 std::set<wxString> existingPins;
1119
1120 for( const SCH_ITEM& item : aSymbol->GetDrawItems() )
1121 {
1122 if( item.Type() == SCH_PIN_T )
1123 existingPins.insert( static_cast<const SCH_PIN&>( item ).GetNumber() );
1124 }
1125
1126 for( const auto& sp : aSigpins )
1127 {
1128 wxString pinNum = wxString::FromUTF8( sp.pin_number );
1129
1130 if( existingPins.count( pinNum ) )
1131 continue;
1132
1133 SCH_PIN* pin = new SCH_PIN( aSymbol );
1134 pin->SetNumber( pinNum );
1135 pin->SetName( wxString::FromUTF8( sp.net_name ) );
1137 pin->SetVisible( false );
1138 pin->SetLength( 0 );
1139 pin->SetPosition( VECTOR2I( 0, 0 ) );
1140 pin->SetShape( GRAPHIC_PINSHAPE::LINE );
1141
1142 aSymbol->AddDrawItem( pin );
1143 existingPins.insert( pinNum );
1144 }
1145}
1146
1147
1149{
1150 switch( aPadsType )
1151 {
1152 case PIN_TYPE::INPUT: return static_cast<int>( ELECTRICAL_PINTYPE::PT_INPUT );
1153 case PIN_TYPE::OUTPUT: return static_cast<int>( ELECTRICAL_PINTYPE::PT_OUTPUT );
1154 case PIN_TYPE::BIDIRECTIONAL: return static_cast<int>( ELECTRICAL_PINTYPE::PT_BIDI );
1155 case PIN_TYPE::TRISTATE: return static_cast<int>( ELECTRICAL_PINTYPE::PT_TRISTATE );
1156 case PIN_TYPE::OPEN_COLLECTOR: return static_cast<int>( ELECTRICAL_PINTYPE::PT_OPENCOLLECTOR );
1157 case PIN_TYPE::OPEN_EMITTER: return static_cast<int>( ELECTRICAL_PINTYPE::PT_OPENEMITTER );
1158 case PIN_TYPE::POWER: return static_cast<int>( ELECTRICAL_PINTYPE::PT_POWER_IN );
1159 case PIN_TYPE::PASSIVE: return static_cast<int>( ELECTRICAL_PINTYPE::PT_PASSIVE );
1161 default: return static_cast<int>( ELECTRICAL_PINTYPE::PT_UNSPECIFIED );
1162 }
1163}
1164
1165
1166bool PADS_SCH_SYMBOL_BUILDER::IsPowerSymbol( const std::string& aName )
1167{
1168 // Convert to uppercase for case-insensitive comparison
1169 std::string upper = aName;
1170 std::transform( upper.begin(), upper.end(), upper.begin(),
1171 []( unsigned char c ) { return std::toupper( c ); } );
1172
1173 // Check for ground variants
1174 if( upper == "GND" || upper == "AGND" || upper == "DGND" || upper == "PGND" ||
1175 upper == "EARTH" || upper == "CHASSIS" || upper == "VSS" || upper == "0V" )
1176 {
1177 return true;
1178 }
1179
1180 // Check for power supply variants
1181 if( upper == "VCC" || upper == "VDD" || upper == "VEE" || upper == "VPP" ||
1182 upper == "VBAT" || upper == "VBUS" || upper == "V+" || upper == "V-" )
1183 {
1184 return true;
1185 }
1186
1187 // Check for voltage patterns like +3V3, +5V, -12V, +V1, -V2, etc.
1188 if( upper.length() >= 2 && ( upper[0] == '+' || upper[0] == '-' ) )
1189 return true;
1190
1191 return false;
1192}
1193
1194
1195std::optional<LIB_ID> PADS_SCH_SYMBOL_BUILDER::GetKiCadPowerSymbolId( const std::string& aPadsName )
1196{
1197 // Convert to uppercase for case-insensitive comparison
1198 std::string upper = aPadsName;
1199 std::transform( upper.begin(), upper.end(), upper.begin(),
1200 []( unsigned char c ) { return std::toupper( c ); } );
1201
1202 // Map common power symbol names to KiCad power library symbols
1203 struct PowerMapping
1204 {
1205 const char* padsName;
1206 const char* kicadSymbol;
1207 };
1208
1209 static const PowerMapping mappings[] = {
1210 { "GND", "GND" },
1211 { "AGND", "GND" },
1212 { "DGND", "GNDD" },
1213 { "PGND", "GNDPWR" },
1214 { "EARTH", "Earth" },
1215 { "CHASSIS", "Chassis" },
1216 { "VSS", "VSS" },
1217 { "0V", "GND" },
1218 { "VCC", "VCC" },
1219 { "VDD", "VDD" },
1220 { "VEE", "VEE" },
1221 { "VPP", "VPP" },
1222 { "VBAT", "VBAT" },
1223 { "VBUS", "VBUS" },
1224 { "V+", "VCC" },
1225 { "V-", "VEE" },
1226 { "+5V", "+5V" },
1227 { "-5V", "-5V" },
1228 { "+3V3", "+3V3" },
1229 { "+3.3V", "+3V3" },
1230 { "+12V", "+12V" },
1231 { "-12V", "-12V" },
1232 { "+15V", "+15V" },
1233 { "-15V", "-15V" },
1234 { "+1V8", "+1V8" },
1235 { "+2V5", "+2V5" },
1236 { "+9V", "+9V" },
1237 { "+24V", "+24V" },
1238 };
1239
1240 for( const auto& mapping : mappings )
1241 {
1242 if( upper == mapping.padsName )
1243 {
1244 LIB_ID libId;
1245 libId.SetLibNickname( "power" );
1246 libId.SetLibItemName( mapping.kicadSymbol );
1247 return libId;
1248 }
1249 }
1250
1251 // Generic fallback for +/- prefixed names not in the table
1252 if( upper.length() >= 2 && upper[0] == '+' )
1253 {
1254 LIB_ID libId;
1255 libId.SetLibNickname( "power" );
1256 libId.SetLibItemName( "VCC" );
1257 return libId;
1258 }
1259
1260 if( upper.length() >= 2 && upper[0] == '-' )
1261 {
1262 LIB_ID libId;
1263 libId.SetLibNickname( "power" );
1264 libId.SetLibItemName( "VEE" );
1265 return libId;
1266 }
1267
1268 return std::nullopt;
1269}
1270
1271} // namespace PADS_SCH
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:123
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:244
void SetCenter(const VECTOR2I &aCenter)
void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
void SetFillMode(FILL_T aFill)
virtual void SetStart(const VECTOR2I &aStart)
Definition eda_shape.h:194
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:532
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:381
void SetTextAngleDegrees(double aOrientation)
Definition eda_text.h:171
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
Definition lib_id.cpp:107
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Definition lib_id.cpp:96
Define a library symbol object.
Definition lib_symbol.h:79
void SetGlobalPower()
void LockUnits(bool aLockUnits)
Set interchangeable the property for symbol units.
Definition lib_symbol.h:277
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:709
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:333
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:162
virtual void SetUnit(int aUnit)
Definition sch_item.h:232
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_shape.cpp:98
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:170
virtual void SetShowPinNames(bool aShow)
Set or clear the pin name visibility flag.
Definition symbol.h:164
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:47
@ FILLED_SHAPE
Fill with object color.
Definition eda_shape.h:61
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:464
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:32
@ PT_INPUT
usual pin input: must be connected
Definition pin_type.h:33
@ PT_OUTPUT
usual output
Definition pin_type.h:34
@ PT_TRISTATE
tri state bus pin
Definition pin_type.h:36
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:35
@ PT_OPENEMITTER
pin type open emitter
Definition pin_type.h:45
@ PT_OPENCOLLECTOR
pin type open collector
Definition pin_type.h:44
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:41
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:39
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:101
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:123
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:107
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:114
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:131
GRAPHIC_PINSHAPE
Definition pin_type.h:80
CITER next(CITER it)
Definition ptree.cpp:120
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:150
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683