KiCad PCB EDA Suite
Loading...
Searching...
No Matches
target3001_sch_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 The 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 2
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 <algorithm>
23#include <cmath>
24#include <set>
25
26#include <wx/filename.h>
27#include <wx/image.h>
28#include <wx/mstream.h>
29
30#include <base_units.h>
31#include <geometry/seg.h>
32#include <lib_id.h>
33#include <lib_symbol.h>
34#include <page_info.h>
35#include <reporter.h>
36#include <bitmap_base.h>
37#include <sch_bitmap.h>
38#include <sch_junction.h>
39#include <sch_label.h>
40#include <sch_line.h>
41#include <sch_pin.h>
42#include <sch_screen.h>
43#include <sch_shape.h>
44#include <sch_sheet.h>
45#include <sch_sheet_path.h>
46#include <sch_symbol.h>
47#include <sch_text.h>
48#include <schematic.h>
49#include <trigo.h>
51
56
57namespace
58{
59
60constexpr int PAGE_MARGIN_MM = 10;
61
62// Keeps imported content on the standard connection grid when it is moved onto the page
63constexpr int PLACEMENT_GRID = 12700;
64
65// Signal of schematic buses, which join their member wires by name rather than by touching
66constexpr int BUS_SIGNAL = 65502;
67
68// Gap that parts touching items of different signals; one mil stays on the imperial grid
69constexpr int SIGNAL_GAP = 254;
70
71// Diagonal steps tried for a free spot before the last one is taken anyway
72constexpr int MAX_DIAGONAL_STEPS = 8;
73
74// Ends of one signal closer than this are one connection drawn off grid
75constexpr int NEAR_MISS = 1000;
76
77// Farthest a signal name is drawn from its wire and still names it
78constexpr int LABEL_REACH = 50800;
79
80const wxString LIB_NAME = wxS( "target3001" );
81
82
83PIN_ORIENTATION pinOrientation( float aDirection )
84{
85 int quadrant = ( (int) std::lround( aDirection / 90.0f ) % 4 + 4 ) % 4;
86
87 switch( quadrant )
88 {
89 case 1: return PIN_ORIENTATION::PIN_UP;
90 case 2: return PIN_ORIENTATION::PIN_LEFT;
91 case 3: return PIN_ORIENTATION::PIN_DOWN;
92 default: return PIN_ORIENTATION::PIN_RIGHT;
93 }
94}
95
96
97ELECTRICAL_PINTYPE pinType( const ELEMENT& aPin )
98{
99 if( aPin.pin.supplyPin )
101
102 switch( aPin.pin.electricalType )
103 {
104 // An unconnected pin wired to a signal still joins it, which KiCad allows only when not internally connected
106 case 1: return ELECTRICAL_PINTYPE::PT_INPUT;
107 case 2: return ELECTRICAL_PINTYPE::PT_OUTPUT;
108 case 3: return ELECTRICAL_PINTYPE::PT_BIDI;
110 case 5: return ELECTRICAL_PINTYPE::PT_POWER_IN;
111 case 6: return ELECTRICAL_PINTYPE::PT_PASSIVE;
112 case 7: return ELECTRICAL_PINTYPE::PT_TRISTATE;
114 }
115}
116
117
118GRAPHIC_PINSHAPE pinShape( const TARGET3001::PIN& aPin )
119{
120 if( aPin.inverted && aPin.clock )
122
123 if( aPin.inverted )
125
126 if( aPin.clock )
128
130}
131
132
133LINE_STYLE lineStyle( uint8_t aDash )
134{
135 switch( aDash )
136 {
137 case 1: return LINE_STYLE::DASH;
138 case 2: return LINE_STYLE::DASHDOT;
139 case 3: return LINE_STYLE::DASHDOTDOT;
140 case 4: return LINE_STYLE::DOT;
141 default: return LINE_STYLE::SOLID;
142 }
143}
144
145
147int textQuadrant( float aDirection )
148{
149 return ( (int) std::lround( aDirection / 90.0f ) % 4 + 4 ) % 4;
150}
151
152
154bool isHiddenText( const ELEMENT& aElem )
155{
156 return ( aElem.base.flags & 1 ) || aElem.text.weight == 0;
157}
158
159
161bool isUnplacedGate( const ELEMENT& aGate )
162{
163 return aGate.base.flags & 1;
164}
165
166
167VECTOR2I wireEnd( const SCH_LINE* aWire, int aEnd )
168{
169 return aEnd ? aWire->GetEndPoint() : aWire->GetStartPoint();
170}
171
172
173void setWireEnd( SCH_LINE* aWire, int aEnd, const VECTOR2I& aPos )
174{
175 if( aEnd )
176 aWire->SetEndPoint( aPos );
177 else
178 aWire->SetStartPoint( aPos );
179}
180
181
183VECTOR2I stepIn( const SCH_LINE* aWire, int aEnd )
184{
185 VECTOR2I end = wireEnd( aWire, aEnd );
186 VECTOR2I span = wireEnd( aWire, 1 - aEnd ) - end;
187
188 if( span.EuclideanNorm() <= 2 * SIGNAL_GAP )
189 return end;
190
191 return end + span.Resize( SIGNAL_GAP );
192}
193
194
195bool passesThrough( const SCH_LINE* aLine, const VECTOR2I& aPos )
196{
197 return !aLine->IsEndPoint( aPos ) && IsPointOnSegment( aLine->GetStartPoint(), aLine->GetEndPoint(), aPos );
198}
199
200
202SPIN_STYLE spinAlong( const VECTOR2I& aDir )
203{
204 if( std::abs( aDir.x ) >= std::abs( aDir.y ) )
205 return aDir.x < 0 ? SPIN_STYLE::LEFT : SPIN_STYLE::RIGHT;
206
207 return aDir.y < 0 ? SPIN_STYLE::UP : SPIN_STYLE::BOTTOM;
208}
209
210
212bool overlaps( const SCH_LINE* aFirst, const SCH_LINE* aSecond )
213{
214 VECTOR2I a = aFirst->GetStartPoint();
215 VECTOR2I b = aFirst->GetEndPoint();
216 VECTOR2I c = aSecond->GetStartPoint();
217 VECTOR2I d = aSecond->GetEndPoint();
218 VECTOR2I dir = b - a;
219
220 if( dir.Cross( c - a ) || dir.Cross( d - a ) )
221 return false;
222
223 auto along = [&]( const VECTOR2I& aPos )
224 {
225 return dir.Dot( aPos - a );
226 };
227
228 return std::min( std::max( along( a ), along( b ) ), std::max( along( c ), along( d ) ) )
229 > std::max( std::min( along( a ), along( b ) ), std::min( along( c ), along( d ) ) );
230}
231
232
239std::pair<int32_t, int32_t> configureText( EDA_TEXT* aText, const ELEMENT& aElem, TARGET3001::FONTS& aFonts,
240 bool aUseRightEnd = true )
241{
242 const TARGET3001::TEXT& src = aElem.text;
243
244 aFonts.Apply( aText, aElem, 100 );
245
246 int quadrant = textQuadrant( src.direction );
247 bool upsideDown = quadrant >= 2;
248 bool fromEnd = upsideDown != ( src.mirrored != 0 );
249
250 aText->SetTextAngle( quadrant % 2 ? ANGLE_VERTICAL : ANGLE_HORIZONTAL );
252
253 // A stored right end lies on the far side of the anchor, so the justification flips with it
254 std::optional<std::pair<int32_t, int32_t>> end = aElem.base.TextRightEnd();
255
256 if( end && aUseRightEnd )
257 {
259 return *end;
260 }
261
263 return { aElem.base.x, aElem.base.y };
264}
265
266} // namespace
267
268
270 const TARGET3001::PROJECT& aProject, const wxString& aFileName,
271 REPORTER* aReporter ) :
272 m_schematic( aSchematic ),
273 m_rootSheet( aRootSheet ),
274 m_project( aProject ),
275 m_fileName( aFileName ),
276 m_reporter( aReporter )
277{
278}
279
280
282{
283 return VECTOR2I( KiROUND( aX / 100.0 ), KiROUND( -aY / 100.0 ) );
284}
285
286
287int TARGET3001_SCH_BUILDER::toSch( int32_t aLength )
288{
289 return KiROUND( aLength / 100.0 );
290}
291
292
294{
295 int sheet = aElem.base.layer - TARGET3001::SCHEMATIC_LAYER_BASE;
296
297 if( sheet < 1 || sheet > TARGET3001::SCHEMATIC_SHEET_COUNT )
298 return 0;
299
300 return sheet;
301}
302
303
305{
306 // Create sheets in order so the lowest numbered one becomes the root sheet
307 std::set<int> used;
308
309 for( const ELEMENT& e : m_project.components )
310 {
311 if( e.type == ELEMENT_TYPE::COMPONENT && e.component )
312 {
313 for( const ELEMENT& s : e.component->symbols )
314 {
315 if( !isUnplacedGate( s ) )
316 used.insert( sheetOf( s ) );
317 }
318 }
319 }
320
321 for( const ELEMENT& e : m_project.signals )
322 {
323 if( e.type == ELEMENT_TYPE::SIGNAL && e.signal )
324 {
325 for( const ELEMENT& c : e.signal->connections )
326 used.insert( sheetOf( c ) );
327 }
328 }
329
330 for( const ELEMENT& e : m_project.schematicItems )
331 used.insert( sheetOf( e ) );
332
333 used.erase( 0 );
334
335 for( int sheet : used )
336 screen( sheet );
337
338 for( const ELEMENT& e : m_project.components )
339 {
340 if( e.type == ELEMENT_TYPE::COMPONENT && e.component )
341 addComponent( e );
342 }
343
344 for( const ELEMENT& e : m_project.signals )
345 {
346 if( e.type == ELEMENT_TYPE::SIGNAL && e.signal )
347 addConnections( e );
348 }
349
350 for( const ELEMENT& e : m_project.schematicItems )
351 addFreeItem( e );
352
353 for( const auto& [sheet, items] : m_netItems )
354 separateSignals( sheet );
355
356 // Parting signals can split one, so its pieces are joined on the final geometry
358
359 finishSheets();
360}
361
362
364{
365 if( !aItem )
366 return;
367
368 BOX2I bbox = aItem->GetBoundingBox();
369 auto it = m_extents.find( aSheet );
370
371 if( it == m_extents.end() )
372 m_extents[aSheet] = bbox;
373 else
374 it->second.Merge( bbox );
375
376 m_pending[aSheet].push_back( aItem );
377}
378
379
380SCH_ITEM* TARGET3001_SCH_BUILDER::makeGraphic( const ELEMENT& aElem, const VECTOR2I& aOrigin, bool aInSymbol ) const
381{
382 const TARGET3001::ELEMENT_BASE& b = aElem.base;
383 SCH_LAYER_ID layer = aInSymbol ? LAYER_DEVICE : LAYER_NOTES;
384 VECTOR2I p0 = toSch( b.x, b.y ) - aOrigin;
385
386 switch( aElem.type )
387 {
388 case ELEMENT_TYPE::LINE:
389 {
390 const TARGET3001::LINE& l = aElem.line;
391 VECTOR2I p1 = toSch( l.x2, l.y2 ) - aOrigin;
392
393 if( !aInSymbol )
394 {
395 SCH_LINE* line = new SCH_LINE( p0, LAYER_NOTES );
396 line->SetEndPoint( p1 );
397 line->SetStroke( STROKE_PARAMS( toSch( l.width ), lineStyle( l.dashStyle ) ) );
398 return line;
399 }
400
401 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY, layer, toSch( l.width ) );
402 shape->AddPoint( p0 );
403 shape->AddPoint( p1 );
404 shape->SetStroke( STROKE_PARAMS( toSch( l.width ), lineStyle( l.dashStyle ) ) );
405 return shape;
406 }
407
408 case ELEMENT_TYPE::RECTANGLE:
409 {
410 if( !aInSymbol )
411 {
412 if( SCH_BITMAP* picture = makePicture( aElem ) )
413 return picture;
414 }
415
416 const TARGET3001::RECTANGLE& r = aElem.rectangle;
417 EDA_ANGLE rot( double( r.direction ), DEGREES_T );
418 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY, layer, 0, FILL_T::FILLED_SHAPE );
419 VECTOR2D corners[4] = { { 0.0, 0.0 }, { double( r.width ), 0.0 },
420 { double( r.width ), double( r.height ) }, { 0.0, double( r.height ) } };
421
422 for( VECTOR2D c : corners )
423 {
424 RotatePoint( c, -rot );
425 shape->AddPoint( toSch( b.x + KiROUND( c.x ), b.y + KiROUND( c.y ) ) - aOrigin );
426 }
427
428 shape->AddPoint( p0 );
429 return shape;
430 }
431
432 case ELEMENT_TYPE::TRIANGLE:
433 {
434 const TARGET3001::TRIANGLE& t = aElem.triangle;
435 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::POLY, layer, 0, FILL_T::FILLED_SHAPE );
436 shape->AddPoint( p0 );
437 shape->AddPoint( toSch( t.x2, t.y2 ) - aOrigin );
438 shape->AddPoint( toSch( t.x3, t.y3 ) - aOrigin );
439 shape->AddPoint( p0 );
440 return shape;
441 }
442
443 case ELEMENT_TYPE::DISC:
444 {
445 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::CIRCLE, layer, 0, FILL_T::FILLED_SHAPE );
446 shape->SetCenter( p0 );
447 shape->SetEnd( p0 + VECTOR2I( toSch( aElem.disc.radius ), 0 ) );
448 return shape;
449 }
450
451 case ELEMENT_TYPE::ARC:
452 {
453 const TARGET3001::ARC& a = aElem.arc;
454 VECTOR2I center = toSch( a.centerX, a.centerY ) - aOrigin;
455 int radius = toSch( a.radius );
456 double sweep = a.Sweep();
457
458 if( sweep >= 360.0 - 1e-6 )
459 {
460 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::CIRCLE, layer, toSch( a.width ) );
461 shape->SetCenter( center );
462 shape->SetEnd( center + VECTOR2I( radius, 0 ) );
463 return shape;
464 }
465
466 auto at = [&]( double aDeg )
467 {
468 return center + VECTOR2I( KiROUND( radius * cos( DEG2RAD( aDeg ) ) ),
469 -KiROUND( radius * sin( DEG2RAD( aDeg ) ) ) );
470 };
471
472 SCH_SHAPE* shape = new SCH_SHAPE( SHAPE_T::ARC, layer, toSch( a.width ) );
473 shape->SetArcGeometry( at( a.startAngle ), at( a.startAngle + sweep / 2.0 ),
474 at( a.startAngle + sweep ) );
475 return shape;
476 }
477
478 case ELEMENT_TYPE::TEXT:
479 {
480 if( isHiddenText( aElem ) )
481 return nullptr;
482
483 wxString content = m_project.FunctionText( aElem.text, true ).value_or( ToWx( aElem.text.text ) );
484
485 SCH_TEXT* text = new SCH_TEXT( p0, content, layer );
486 std::pair<int32_t, int32_t> pos = configureText( text, aElem, m_fonts );
487 text->SetPosition( toSch( pos.first, pos.second ) - aOrigin + TARGET3001::FONTS::BaselineShift( *text ) );
488 return text;
489 }
490
491 default:
492 return nullptr;
493 }
494}
495
496
498{
499 if( aElem.type != ELEMENT_TYPE::RECTANGLE )
500 return nullptr;
501
502 const TARGET3001::RECTANGLE& r = aElem.rectangle;
503 std::vector<uint8_t> data = aElem.base.Picture();
504 VECTOR2I size( std::abs( toSch( r.width ) ), std::abs( toSch( r.height ) ) );
505 wxImage image;
506
507 if( data.empty() || size.x == 0 || size.y == 0 )
508 return nullptr;
509
510 wxMemoryInputStream stream( data.data(), data.size() );
511
512 if( !image.LoadFile( stream, wxBITMAP_TYPE_ANY ) )
513 return nullptr;
514
515 // The picture is stretched over its rectangle; KiCad only scales images uniformly
516 int w = image.GetWidth();
517 int h = image.GetHeight();
518 int stretchedW = std::max( w, KiROUND( double( h ) * size.x / size.y ) );
519 int stretchedH = std::max( h, KiROUND( double( w ) * size.y / size.x ) );
520
521 if( stretchedW > w + 1 || stretchedH > h + 1 )
522 image.Rescale( stretchedW, stretchedH, wxIMAGE_QUALITY_HIGH );
523
524 EDA_ANGLE rot( double( r.direction ), DEGREES_T );
525 VECTOR2D half( r.width / 2.0, r.height / 2.0 );
526 RotatePoint( half, -rot );
527
528 SCH_BITMAP* bitmap = new SCH_BITMAP();
529 REFERENCE_IMAGE& ref = bitmap->GetReferenceImage();
530
531 if( !ref.SetImage( image ) )
532 {
533 delete bitmap;
534 return nullptr;
535 }
536
537 ref.MutableImage().SetImageType( image.GetType() );
538 ref.SetWidth( size.x );
539
540 VECTOR2I center = toSch( aElem.base.x + KiROUND( half.x ), aElem.base.y + KiROUND( half.y ) );
541 ref.SetPosition( center );
542
543 if( !rot.IsZero() )
544 ref.Rotate( center, rot );
545
546 return bitmap;
547}
548
549
551{
552 const TARGET3001::COMPONENT& comp = *aComponent.component;
553 std::vector<const ELEMENT*> gates;
554
555 for( const ELEMENT& s : comp.symbols )
556 {
557 if( s.type == ELEMENT_TYPE::SYMBOL && s.symbol && sheetOf( s ) > 0 )
558 gates.push_back( &s );
559 }
560
561 if( gates.empty() )
562 return;
563
564 std::stable_sort( gates.begin(), gates.end(),
565 []( const ELEMENT* a, const ELEMENT* b )
566 {
567 return a->symbol->gateOrdinal < b->symbol->gateOrdinal;
568 } );
569
570 bool hasPackage = std::any_of( comp.packageItems.begin(), comp.packageItems.end(),
571 []( const ELEMENT& e ) { return e.type == ELEMENT_TYPE::PACKAGE; } );
572 bool allSupply = true;
573 int supplySignal = 0;
574
575 for( const ELEMENT* gate : gates )
576 {
577 for( const ELEMENT& child : gate->symbol->children )
578 {
579 if( child.type != ELEMENT_TYPE::PIN )
580 continue;
581
582 if( !child.pin.supplyPin )
583 allSupply = false;
584 else if( !supplySignal )
585 supplySignal = child.base.signal;
586 }
587 }
588
589 bool isPower = !hasPackage && allSupply && supplySignal;
590
591 wxString reference = ToWx( comp.prefix ).Trim().Trim( false );
592 uint16_t number = comp.referenceExtension.value_or( comp.referenceNumber );
593
594 if( isPower )
595 reference = wxString::Format( wxS( "#PWR%03d" ), ++m_powerCount );
596 else if( number )
597 reference << number;
598
599 wxString value = ToWx( comp.value );
600
601 const ELEMENT* sig = isPower ? m_project.FindSignal( supplySignal ) : nullptr;
602
603 if( sig && !sig->signal->name.empty() )
604 value = ToWx( sig->signal->name );
605
606 // Each placed component gets its own library symbol because gate geometry is stored as drawn
607 wxString symName = ToWx( comp.name );
608
609 if( symName.IsEmpty() )
610 symName = reference;
611
612 symName = wxString::Format( wxS( "%s_%d" ), symName, int( aComponent.base.component ) );
613 symName = LIB_ID::FixIllegalChars( symName, false ).wx_str();
614 symName.Replace( wxS( "/" ), wxS( "_" ) );
615
616 LIB_SYMBOL* lib = new LIB_SYMBOL( symName );
617 lib->SetLibId( LIB_ID( LIB_NAME, symName ) );
618 lib->SetUnitCount( int( gates.size() ), false );
619 lib->GetReferenceField().SetText( reference );
620 lib->GetValueField().SetText( value );
621
622 if( isPower )
623 lib->SetGlobalPower();
624
625 std::map<uint16_t, wxString> padNumbers;
626
627 for( const ELEMENT& item : comp.packageItems )
628 {
629 if( item.type == ELEMENT_TYPE::PAD )
630 padNumbers.emplace( item.pad.number, PadNumber( item ) );
631 }
632
633 addGateBodies( lib, gates, true, padNumbers );
634
635 for( size_t g = 0; g < gates.size(); g++ )
636 {
637 const ELEMENT& gate = *gates[g];
638
639 if( isUnplacedGate( gate ) )
640 continue;
641
643 path.push_back( m_sheets.at( sheetOf( gate ) ) );
644
645 SCH_SYMBOL* symbol = new SCH_SYMBOL( *lib, lib->GetLibId(), &path, int( g ) + 1, 0,
646 toSch( gate.base.x, gate.base.y ) );
647 symbol->SetLibSymbol( new LIB_SYMBOL( *lib ) );
648 symbol->SetRef( &path, reference );
649 symbol->GetField( FIELD_T::REFERENCE )->SetText( reference );
650 symbol->GetField( FIELD_T::VALUE )->SetText( value );
651
652 if( !comp.package.empty() )
653 symbol->SetFootprintFieldText( LIB_NAME + wxS( ":" ) + ToWx( comp.package ) );
654
655 bool refShown = false;
656 bool valueShown = false;
657
658 for( const ELEMENT& child : gate.symbol->children )
659 {
660 if( child.type != ELEMENT_TYPE::TEXT )
661 continue;
662
663 FIELD_T id;
664
665 if( child.text.function == uint8_t( TEXT_FUNCTION::REFERENCE ) )
667 else if( child.text.function == uint8_t( TEXT_FUNCTION::VALUE ) )
668 id = FIELD_T::VALUE;
669 else
670 continue;
671
672 SCH_FIELD* field = symbol->GetField( id );
673 std::pair<int32_t, int32_t> pos = configureText( field, child, m_fonts );
674 field->SetPosition( toSch( pos.first, pos.second ) + TARGET3001::FONTS::BaselineShift( *field ) );
675 field->SetVisible( !isHiddenText( child ) );
676 ( id == FIELD_T::REFERENCE ? refShown : valueShown ) = !isHiddenText( child );
677 }
678
679 if( !refShown )
680 symbol->GetField( FIELD_T::REFERENCE )->SetVisible( false );
681
682 if( !valueShown )
683 symbol->GetField( FIELD_T::VALUE )->SetVisible( false );
684
685 addToSheet( sheetOf( gate ), symbol );
686
687 if( isPower )
688 m_powerSheets[supplySignal].insert( sheetOf( gate ) );
689
690 for( const ELEMENT& child : gate.symbol->children )
691 {
692 if( SCH_BITMAP* picture = makePicture( child ) )
693 addToSheet( sheetOf( gate ), picture );
694
695 // An unconnected pin belongs to no signal, so it gets one of its own
696 if( child.type == ELEMENT_TYPE::PIN )
697 {
698 int signal = child.base.signal ? int( child.base.signal ) : -( ++m_unconnectedPins );
699 m_pinSignals[sheetOf( gate )].emplace_back( toSch( child.base.x, child.base.y ), signal );
700
701 if( child.base.signal )
702 {
703 m_pinEnds[signal].push_back(
704 { sheetOf( gate ), toSch( child.base.x, child.base.y ), child.pin.direction, isPower } );
705 }
706 }
707 }
708 }
709
710 delete lib;
711}
712
713
714void TARGET3001_SCH_BUILDER::addGateBodies( LIB_SYMBOL* aLib, const std::vector<const ELEMENT*>& aGates,
715 bool aFieldTexts, const std::map<uint16_t, wxString>& aPadNumbers ) const
716{
717 bool showNumbers = false;
718 bool showNames = false;
719 std::vector<SCH_PIN*> hiddenNames;
720
721 for( size_t g = 0; g < aGates.size(); g++ )
722 {
723 const ELEMENT& gate = *aGates[g];
724 VECTOR2I origin = toSch( gate.base.x, gate.base.y );
725 int unit = int( g ) + 1;
726
727 for( const ELEMENT& child : gate.symbol->children )
728 {
729 if( child.type == ELEMENT_TYPE::PIN )
730 {
731 const TARGET3001::PIN& src = child.pin;
732 SCH_PIN* pin = new SCH_PIN( aLib );
733 wxString name;
734 bool nameShown = false;
735
736 for( const ELEMENT& pc : child.children )
737 {
738 if( pc.type == ELEMENT_TYPE::TEXT && pc.text.function == uint8_t( TEXT_FUNCTION::PIN_NAME ) )
739 {
740 name = ToWx( pc.text.text );
741 nameShown = !isHiddenText( pc ) && !name.IsEmpty();
742
743 if( nameShown )
744 {
745 SCH_TEXT probe( VECTOR2I( 0, 0 ), name );
746 m_fonts.Apply( &probe, pc, 100 );
747 pin->SetNameTextSize( probe.GetTextHeight() );
748 }
749 }
750 }
751
752 pin->SetPosition( toSch( child.base.x, child.base.y ) - origin );
753 pin->SetOrientation( pinOrientation( src.direction ) );
754 pin->SetLength( toSch( src.length ) );
755 pin->SetType( pinType( child ) );
756 pin->SetShape( pinShape( src ) );
757 pin->SetName( name.IsEmpty() ? wxString( wxS( "~" ) ) : name );
758 pin->SetUnit( unit );
759
760 // The footprint pad decides the number so pins and pads connect; the pin's PADNAME is what it shows
761 auto pad = aPadNumbers.find( src.pinNumber );
762 const std::string* padName = child.base.FindProp( "PADNAME" );
763
764 if( pad != aPadNumbers.end() )
765 pin->SetNumber( pad->second );
766 else if( padName && !padName->empty() )
767 pin->SetNumber( ToWx( *padName ) );
768 else
769 pin->SetNumber( wxString::Format( wxS( "%u" ), src.pinNumber ) );
770
771 if( !nameShown && !name.IsEmpty() )
772 hiddenNames.push_back( pin );
773
774 // KiCad shows names and numbers per symbol, so one shown pin shows them all
775 showNumbers |= src.showNumber != 0;
776 showNames |= nameShown;
777 aLib->AddDrawItem( pin, false );
778 continue;
779 }
780
781 if( aFieldTexts && child.type == ELEMENT_TYPE::TEXT
782 && ( child.text.function == uint8_t( TEXT_FUNCTION::REFERENCE )
783 || child.text.function == uint8_t( TEXT_FUNCTION::VALUE ) ) )
784 {
785 continue;
786 }
787
788 // Library symbols cannot hold images; placed gates put the picture on their sheet
789 if( child.type == ELEMENT_TYPE::RECTANGLE && child.base.FindProp( "JPEG_PICTURE" ) )
790 continue;
791
792 if( SCH_ITEM* item = makeGraphic( child, origin, true ) )
793 {
794 item->SetUnit( unit );
795 aLib->AddDrawItem( item, false );
796 }
797 }
798 }
799
800 // Names are hidden per pin in the source but per symbol in KiCad
801 if( showNames )
802 {
803 for( SCH_PIN* pin : hiddenNames )
804 pin->SetName( wxS( "~" ) );
805 }
806
807 aLib->GetDrawItems().sort();
808 aLib->SetShowPinNumbers( showNumbers );
809 aLib->SetShowPinNames( showNames );
810}
811
812
814{
815 wxString name = ToWx( aSignal.signal->name );
816 bool isBus = aSignal.base.signal == BUS_SIGNAL;
817 bool global = !isBus && joinsGlobally( aSignal );
818
819 if( global )
820 m_globalSignals.insert( aSignal.base.signal );
821
822 for( const ELEMENT& e : aSignal.signal->connections )
823 {
824 int sheet = sheetOf( e );
825
826 if( sheet == 0 )
827 continue;
828
829 const TARGET3001::ELEMENT_BASE& b = e.base;
830
831 switch( e.type )
832 {
833 case ELEMENT_TYPE::LINE:
834 {
835 SCH_LINE* wire = new SCH_LINE( toSch( b.x, b.y ), isBus ? LAYER_BUS : LAYER_WIRE );
836 wire->SetEndPoint( toSch( e.line.x2, e.line.y2 ) );
837 addNetItem( sheet, wire, aSignal.base.signal );
838 break;
839 }
840
841 case ELEMENT_TYPE::DISC:
842 addNetItem( sheet, new SCH_JUNCTION( toSch( b.x, b.y ), toSch( 2 * e.disc.radius ) ),
843 aSignal.base.signal );
844 break;
845
846 case ELEMENT_TYPE::TEXT:
847 {
848 bool signalName = e.text.function == uint8_t( TEXT_FUNCTION::SIGNAL_NAME );
849
850 // Labels carry connectivity between wire groups, so a hidden signal name still becomes one
851 if( isHiddenText( e ) && !signalName )
852 break;
853
854 // The name is drawn beside its wire; a label joins only where it touches
855 std::optional<VECTOR2I> anchor;
856
857 if( signalName )
858 anchor = labelAnchor( aSignal, sheet, toSch( b.x, b.y ) );
859
860 if( anchor )
861 {
862 SCH_LABEL_BASE* label = nullptr;
863
864 if( global )
865 label = new SCH_GLOBALLABEL( *anchor, name );
866 else
867 label = new SCH_LABEL( *anchor, name );
868
869 configureText( label, e, m_fonts, false );
870 addNetItem( sheet, label, aSignal.base.signal );
871 }
872 else
873 {
874 addToSheet( sheet, makeGraphic( e, VECTOR2I( 0, 0 ), false ) );
875 }
876
877 break;
878 }
879
880 default:
881 addToSheet( sheet, makeGraphic( e, VECTOR2I( 0, 0 ), false ) );
882 break;
883 }
884 }
885}
886
887
889{
890 if( aSignal.signal->name.empty() )
891 return false;
892
893 // Supply symbols name their net globally, which a local label would not join
894 if( m_powerSheets.count( aSignal.base.signal ) )
895 return true;
896
897 std::set<int> sheets;
898
899 for( const ELEMENT& e : aSignal.signal->connections )
900 {
901 if( sheetOf( e ) )
902 sheets.insert( sheetOf( e ) );
903 }
904
905 if( auto it = m_pinEnds.find( aSignal.base.signal ); it != m_pinEnds.end() )
906 {
907 for( const PIN_END& pin : it->second )
908 sheets.insert( pin.sheet );
909 }
910
911 return sheets.size() > 1;
912}
913
914
915std::optional<VECTOR2I> TARGET3001_SCH_BUILDER::labelAnchor( const ELEMENT& aSignal, int aSheet,
916 const VECTOR2I& aPos ) const
917{
918 std::optional<VECTOR2I> best;
919
920 auto consider = [&]( const VECTOR2I& aCandidate )
921 {
922 SEG::ecoord dist = ( aCandidate - aPos ).SquaredEuclideanNorm();
923
924 if( dist <= SEG::Square( LABEL_REACH ) && ( !best || dist < ( *best - aPos ).SquaredEuclideanNorm() ) )
925 best = aCandidate;
926 };
927
928 for( const ELEMENT& e : aSignal.signal->connections )
929 {
930 if( e.type != ELEMENT_TYPE::LINE || sheetOf( e ) != aSheet )
931 continue;
932
933 SEG wire( toSch( e.base.x, e.base.y ), toSch( e.line.x2, e.line.y2 ) );
934 VECTOR2I nearest = wire.NearestPoint( aPos );
935
936 // Rounding can leave the point beside a slanted wire, so it falls back to the nearer end
937 if( ( nearest - wire.A ).Cross( wire.B - wire.A ) != 0 )
938 {
939 consider( wire.A );
940 consider( wire.B );
941 }
942 else
943 {
944 consider( nearest );
945 }
946 }
947
948 if( auto it = m_pinEnds.find( aSignal.base.signal ); it != m_pinEnds.end() )
949 {
950 for( const PIN_END& pin : it->second )
951 {
952 if( pin.sheet == aSheet )
953 consider( pin.pos );
954 }
955 }
956
957 return best;
958}
959
960
962{
963 std::map<int, std::map<int, std::vector<SCH_ITEM*>>> bySignal;
964
965 for( const auto& [sheet, items] : m_netItems )
966 {
967 for( const auto& [item, signal] : items )
968 bySignal[signal][sheet].push_back( item );
969 }
970
971 for( const auto& [signal, pins] : m_pinEnds )
972 {
973 if( signal != BUS_SIGNAL )
974 joinPieces( signal, bySignal[signal] );
975 }
976}
977
978
979void TARGET3001_SCH_BUILDER::joinPieces( int aSignal, const std::map<int, std::vector<SCH_ITEM*>>& aItems )
980{
981 const std::vector<PIN_END>& pins = m_pinEnds.at( aSignal );
982 bool global = m_globalSignals.count( aSignal ) > 0;
983 bool anyNamed = false;
984 std::set<int> sheets;
985
986 // An unnamed piece takes its label on a free wire end, else on its pin
987 struct PIECE
988 {
989 const PIN_END* pin;
990 std::vector<std::pair<VECTOR2I, VECTOR2I>> ends;
991 };
992
993 std::vector<PIECE> unnamed;
994
995 // Only pieces holding a pin matter to the netlist
996 for( const PIN_END& pin : pins )
997 sheets.insert( pin.sheet );
998
999 auto isFree = [&]( int aSheet, const VECTOR2I& aPos )
1000 {
1001 for( const auto& [pos, pinSignal] : m_pinSignals[aSheet] )
1002 {
1003 if( pos == aPos && pinSignal != aSignal )
1004 return false;
1005 }
1006
1007 for( const auto& [item, itemSignal] : m_netItems[aSheet] )
1008 {
1009 if( itemSignal == aSignal )
1010 continue;
1011
1012 if( item->Type() != SCH_LINE_T )
1013 {
1014 if( item->GetPosition() == aPos )
1015 return false;
1016
1017 continue;
1018 }
1019
1020 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1021
1022 if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), aPos ) )
1023 return false;
1024 }
1025
1026 return true;
1027 };
1028
1029 for( int sheet : sheets )
1030 {
1031 std::vector<SEG> wires;
1032 std::vector<VECTOR2I> points;
1033 std::set<VECTOR2I> names;
1034 std::set<VECTOR2I> pinPoints;
1035
1036 if( auto it = aItems.find( sheet ); it != aItems.end() )
1037 {
1038 for( SCH_ITEM* item : it->second )
1039 {
1040 if( item->Type() == SCH_LINE_T )
1041 {
1042 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1043 wires.emplace_back( line->GetStartPoint(), line->GetEndPoint() );
1044 }
1045 else if( dynamic_cast<SCH_LABEL_BASE*>( item ) )
1046 {
1047 names.insert( item->GetPosition() );
1048 }
1049 else
1050 {
1051 points.push_back( item->GetPosition() );
1052 }
1053 }
1054 }
1055
1056 for( const PIN_END& pin : pins )
1057 {
1058 if( pin.sheet == sheet )
1059 pinPoints.insert( pin.pos );
1060 }
1061
1062 std::map<VECTOR2I, int> index;
1063 std::vector<int> parent;
1064
1065 auto node = [&]( const VECTOR2I& aPos )
1066 {
1067 auto [it, inserted] = index.emplace( aPos, int( parent.size() ) );
1068
1069 if( inserted )
1070 parent.push_back( it->second );
1071
1072 return it->second;
1073 };
1074
1075 auto find = [&]( int aNode )
1076 {
1077 while( parent[aNode] != aNode )
1078 aNode = parent[aNode] = parent[parent[aNode]];
1079
1080 return aNode;
1081 };
1082
1083 auto unite = [&]( int aFirst, int aSecond )
1084 {
1085 parent[find( aFirst )] = find( aSecond );
1086 };
1087
1088 std::vector<VECTOR2I> ends( pinPoints.begin(), pinPoints.end() );
1089
1090 for( const SEG& wire : wires )
1091 {
1092 int start = node( wire.A );
1093 unite( start, node( wire.B ) );
1094 ends.push_back( wire.A );
1095 ends.push_back( wire.B );
1096 }
1097
1098 for( const VECTOR2I& pos : points )
1099 node( pos );
1100
1101 for( const VECTOR2I& pos : names )
1102 node( pos );
1103
1104 for( const VECTOR2I& pos : pinPoints )
1105 node( pos );
1106
1107 // A point lying inside a wire joins it
1108 for( const auto& [pos, id] : index )
1109 {
1110 for( const SEG& wire : wires )
1111 {
1112 if( IsPointOnSegment( wire.A, wire.B, pos ) )
1113 unite( id, index.at( wire.A ) );
1114 }
1115 }
1116
1117 std::sort( ends.begin(), ends.end(),
1118 []( const VECTOR2I& a, const VECTOR2I& b )
1119 {
1120 return a.x < b.x || ( a.x == b.x && a.y < b.y );
1121 } );
1122
1123 ends.erase( std::unique( ends.begin(), ends.end() ), ends.end() );
1124
1125 for( size_t i = 0; i < ends.size(); i++ )
1126 {
1127 for( size_t j = i + 1; j < ends.size() && ends[j].x - ends[i].x < NEAR_MISS; j++ )
1128 {
1129 int first = index.at( ends[i] );
1130 int second = index.at( ends[j] );
1131
1132 if( ( ends[j] - ends[i] ).EuclideanNorm() >= NEAR_MISS || find( first ) == find( second ) )
1133 continue;
1134
1135 SCH_LINE* stub = new SCH_LINE( ends[i], LAYER_WIRE );
1136 stub->SetEndPoint( ends[j] );
1137 addNetItem( sheet, stub, aSignal );
1138 unite( first, second );
1139 }
1140 }
1141
1142 std::set<int> named;
1143
1144 for( const VECTOR2I& pos : names )
1145 named.insert( find( index.at( pos ) ) );
1146
1147 for( const PIN_END& pin : pins )
1148 {
1149 if( global && pin.power && pin.sheet == sheet )
1150 named.insert( find( index.at( pin.pos ) ) );
1151 }
1152
1153 std::map<VECTOR2I, int> endCount;
1154 std::map<VECTOR2I, VECTOR2I> outward;
1155
1156 for( const SEG& wire : wires )
1157 {
1158 endCount[wire.A]++;
1159 endCount[wire.B]++;
1160 outward[wire.A] = wire.A - wire.B;
1161 outward[wire.B] = wire.B - wire.A;
1162 }
1163
1164 std::set<int> seen;
1165
1166 for( const PIN_END& pin : pins )
1167 {
1168 if( pin.sheet != sheet )
1169 continue;
1170
1171 int root = find( index.at( pin.pos ) );
1172
1173 if( named.count( root ) )
1174 {
1175 anyNamed = true;
1176 continue;
1177 }
1178
1179 if( !seen.insert( root ).second )
1180 continue;
1181
1182 PIECE piece{ &pin, {} };
1183
1184 for( const auto& [pos, count] : endCount )
1185 {
1186 if( count == 1 && !pinPoints.count( pos ) && find( index.at( pos ) ) == root )
1187 piece.ends.emplace_back( pos, outward.at( pos ) );
1188 }
1189
1190 unnamed.push_back( std::move( piece ) );
1191 }
1192 }
1193
1194 const ELEMENT* sig = m_project.FindSignal( aSignal );
1195
1196 if( unnamed.size() + ( anyNamed ? 1 : 0 ) < 2 || !sig || sig->signal->name.empty() )
1197 return;
1198
1199 // A name another signal shares would join the two
1200 for( const ELEMENT& e : m_project.signals )
1201 {
1202 if( &e != sig && e.type == ELEMENT_TYPE::SIGNAL && e.signal && e.signal->name == sig->signal->name )
1203 return;
1204 }
1205
1206 wxString name = ToWx( sig->signal->name );
1207
1208 for( const PIECE& piece : unnamed )
1209 {
1210 int sheet = piece.pin->sheet;
1211 VECTOR2I pos = piece.pin->pos;
1213
1214 // Text on a pin runs away from the body
1215 switch( pinOrientation( piece.pin->direction ) )
1216 {
1217 case PIN_ORIENTATION::PIN_RIGHT: spin = SPIN_STYLE::LEFT; break;
1218 case PIN_ORIENTATION::PIN_UP: spin = SPIN_STYLE::BOTTOM; break;
1219 case PIN_ORIENTATION::PIN_DOWN: spin = SPIN_STYLE::UP; break;
1220 default: spin = SPIN_STYLE::RIGHT; break;
1221 }
1222
1223 for( const auto& [end, dir] : piece.ends )
1224 {
1225 if( isFree( sheet, end ) )
1226 {
1227 pos = end;
1228 spin = spinAlong( dir );
1229 break;
1230 }
1231 }
1232
1233 SCH_LABEL_BASE* label = nullptr;
1234
1235 if( global )
1236 label = new SCH_GLOBALLABEL( pos, name );
1237 else
1238 label = new SCH_LABEL( pos, name );
1239
1240 label->SetSpinStyle( spin );
1241 addNetItem( sheet, label, aSignal );
1242 }
1243}
1244
1245
1246void TARGET3001_SCH_BUILDER::addNetItem( int aSheet, SCH_ITEM* aItem, int aSignal )
1247{
1248 addToSheet( aSheet, aItem );
1249 m_netItems[aSheet].emplace_back( aItem, aSignal );
1250}
1251
1252
1254{
1255 std::vector<std::pair<SCH_LINE*, int>> wires;
1256 std::vector<SCH_LINE*> buses;
1257 std::vector<std::pair<SCH_ITEM*, int>> points;
1258
1259 for( const auto& [item, signal] : m_netItems[aSheet] )
1260 {
1261 if( item->Type() != SCH_LINE_T )
1262 points.emplace_back( item, signal );
1263 else if( signal == BUS_SIGNAL )
1264 buses.push_back( static_cast<SCH_LINE*>( item ) );
1265 else
1266 wires.emplace_back( static_cast<SCH_LINE*>( item ), signal );
1267 }
1268
1269 // A bus joins its members by name, so each wire leaving it needs a label of its signal
1270 for( const auto& [wire, signal] : wires )
1271 {
1272 for( int end : { 0, 1 } )
1273 {
1274 VECTOR2I pos = wireEnd( wire, end );
1275 VECTOR2I moved = stepIn( wire, end );
1276
1277 bool onBus = std::any_of( buses.begin(), buses.end(),
1278 [&]( SCH_LINE* bus )
1279 {
1280 return IsPointOnSegment( bus->GetStartPoint(), bus->GetEndPoint(), pos );
1281 } );
1282
1283 if( !onBus || moved == pos )
1284 continue;
1285
1286 setWireEnd( wire, end, moved );
1287 bool labeled = false;
1288
1289 for( const auto& [item, itemSignal] : points )
1290 {
1291 if( itemSignal != signal )
1292 continue;
1293
1294 if( item->GetPosition() == pos )
1295 item->SetPosition( moved );
1296
1297 labeled |= dynamic_cast<SCH_LABEL_BASE*>( item )
1298 && IsPointOnSegment( wire->GetStartPoint(), wire->GetEndPoint(), item->GetPosition() );
1299 }
1300
1301 const ELEMENT* sig = m_project.FindSignal( signal );
1302
1303 if( labeled || !sig || sig->signal->name.empty() )
1304 continue;
1305
1306 wxString name = ToWx( sig->signal->name );
1307 SCH_LABEL_BASE* label = nullptr;
1308
1309 if( m_globalSignals.count( signal ) )
1310 label = new SCH_GLOBALLABEL( moved, name );
1311 else
1312 label = new SCH_LABEL( moved, name );
1313
1314 // The text runs along the wire, away from the bus
1315 label->SetSpinStyle( spinAlong( wireEnd( wire, 1 - end ) - moved ) );
1316
1317 addNetItem( aSheet, label, signal );
1318 points.emplace_back( label, signal );
1319 }
1320 }
1321
1322 // A junction or label inside a wire joins a branch to it, which a shifted wire would lose
1323 auto hasBranch = [&]( const std::pair<SCH_LINE*, int>& aWire )
1324 {
1325 return std::any_of( points.begin(), points.end(),
1326 [&]( const std::pair<SCH_ITEM*, int>& aPoint )
1327 {
1328 return aPoint.second == aWire.second
1329 && passesThrough( aWire.first, aPoint.first->GetPosition() );
1330 } );
1331 };
1332
1333 // Overlapping wires of different signals would be merged into one, so one of them steps aside; ends left
1334 // inside the other wire are parted below with everything else
1335 size_t drawn = wires.size();
1336
1337 for( size_t i = 0; i < drawn; i++ )
1338 {
1339 for( size_t j = i + 1; j < drawn; j++ )
1340 {
1341 if( wires[i].second == wires[j].second || !overlaps( wires[i].first, wires[j].first ) )
1342 continue;
1343
1344 bool firstShorter = wires[i].first->GetLength() <= wires[j].first->GetLength();
1345 std::pair<SCH_LINE*, int> pick = firstShorter ? wires[i] : wires[j];
1346
1347 if( hasBranch( pick ) )
1348 pick = firstShorter ? wires[j] : wires[i];
1349
1350 SCH_LINE* wire = pick.first;
1351
1352 if( hasBranch( pick ) || wire->GetLength() <= 2 * SIGNAL_GAP )
1353 continue;
1354
1355 // Stubs join the shifted run back to its ends, which stay where they connect
1356 VECTOR2I start = wire->GetStartPoint();
1357 VECTOR2I end = wire->GetEndPoint();
1358 VECTOR2I side = VECTOR2I( start.y - end.y, end.x - start.x ).Resize( SIGNAL_GAP );
1359
1360 for( const auto& [from, to] : { std::pair( start, start + side ), std::pair( end + side, end ) } )
1361 {
1362 SCH_LINE* stub = new SCH_LINE( *wire );
1363 stub->SetStartPoint( from );
1364 stub->SetEndPoint( to );
1365 addNetItem( aSheet, stub, pick.second );
1366 wires.emplace_back( stub, pick.second );
1367 }
1368
1369 wire->SetStartPoint( start + side );
1370 wire->SetEndPoint( end + side );
1371 }
1372 }
1373
1374 // What KiCad joins at each point: everything there and every line passing through. A fixed member is a pin,
1375 // a bus or a line passing through; only pins and buses have no item
1376 struct MEMBER
1377 {
1378 int signal;
1379 SCH_ITEM* item;
1380 int end;
1381 bool fixed;
1382 };
1383
1384 std::map<VECTOR2I, std::vector<MEMBER>> at;
1385 std::set<VECTOR2I> busEnds;
1386
1387 for( const auto& [wire, signal] : wires )
1388 {
1389 for( int end : { 0, 1 } )
1390 at[wireEnd( wire, end )].push_back( { signal, wire, end, false } );
1391 }
1392
1393 for( const auto& [pos, signal] : m_pinSignals[aSheet] )
1394 at[pos].push_back( { signal, nullptr, -1, true } );
1395
1396 for( const auto& [item, signal] : points )
1397 at[item->GetPosition()].push_back( { signal, item, -1, false } );
1398
1399 for( SCH_LINE* bus : buses )
1400 {
1401 busEnds.insert( bus->GetStartPoint() );
1402 busEnds.insert( bus->GetEndPoint() );
1403 }
1404
1405 for( auto& [pos, members] : at )
1406 {
1407 // Wires never join buses, but pins, junctions and labels join both
1408 bool joinsBus = std::any_of( members.begin(), members.end(),
1409 []( const MEMBER& m )
1410 {
1411 return m.end < 0;
1412 } );
1413
1414 if( joinsBus && busEnds.count( pos ) )
1415 members.push_back( { BUS_SIGNAL, nullptr, -1, true } );
1416
1417 for( const auto& [wire, signal] : wires )
1418 {
1419 if( passesThrough( wire, pos ) )
1420 members.push_back( { signal, wire, -1, true } );
1421 }
1422
1423 for( SCH_LINE* bus : buses )
1424 {
1425 if( joinsBus && passesThrough( bus, pos ) )
1426 members.push_back( { BUS_SIGNAL, bus, -1, true } );
1427 }
1428 }
1429
1430 // A side is free when nothing of any signal lies there
1431 auto isFree = [&]( const VECTOR2I& aPos )
1432 {
1433 auto onLine = [&]( SCH_LINE* aLine )
1434 {
1435 return IsPointOnSegment( aLine->GetStartPoint(), aLine->GetEndPoint(), aPos );
1436 };
1437
1438 return !at.count( aPos ) && std::none_of( buses.begin(), buses.end(), onLine )
1439 && std::none_of( wires.begin(), wires.end(),
1440 [&]( const std::pair<SCH_LINE*, int>& aWire )
1441 {
1442 return onLine( aWire.first );
1443 } );
1444 };
1445
1446 // A wire bent earlier may have handed this end to one of its new pieces
1447 auto endAt = [&]( const MEMBER* aMember, const VECTOR2I& aPos ) -> std::pair<SCH_LINE*, int>
1448 {
1449 SCH_LINE* line = static_cast<SCH_LINE*>( aMember->item );
1450
1451 if( wireEnd( line, aMember->end ) == aPos )
1452 return { line, aMember->end };
1453
1454 for( const auto& [wire, signal] : wires )
1455 {
1456 for( int end : { 0, 1 } )
1457 {
1458 if( signal == aMember->signal && wireEnd( wire, end ) == aPos )
1459 return { wire, end };
1460 }
1461 }
1462
1463 return { line, aMember->end };
1464 };
1465
1466 for( const auto& [pos, members] : at )
1467 {
1468 std::map<int, std::vector<const MEMBER*>> groups;
1469 std::set<int> fixed;
1470 std::set<int> pinned;
1471
1472 for( const MEMBER& m : members )
1473 {
1474 groups[m.signal].push_back( &m );
1475
1476 if( m.fixed )
1477 fixed.insert( m.signal );
1478
1479 if( m.fixed && !m.item )
1480 pinned.insert( m.signal );
1481 }
1482
1483 // Pins of two signals on one spot cannot be parted without moving a symbol
1484 if( groups.size() < 2 || pinned.size() > 1 )
1485 continue;
1486
1487 int keeper = groups.begin()->first;
1488
1489 for( const auto& [signal, group] : groups )
1490 {
1491 if( fixed.count( signal ) > fixed.count( keeper )
1492 || ( fixed.count( signal ) == fixed.count( keeper ) && group.size() > groups.at( keeper ).size() ) )
1493 {
1494 keeper = signal;
1495 }
1496 }
1497
1498 if( !pinned.empty() )
1499 keeper = *pinned.begin();
1500
1501 int step = 0;
1502
1503 for( const auto& [signal, group] : groups )
1504 {
1505 if( signal == keeper )
1506 continue;
1507
1508 VECTOR2I moved = pos;
1509
1510 if( fixed.count( signal ) )
1511 {
1512 // Lines of this signal passing through bend around the point, taking its other items along
1513 std::optional<VECTOR2I> side = bendAround( aSheet, signal, pos, wires, isFree );
1514
1515 if( !side )
1516 continue;
1517
1518 moved = pos + *side;
1519 }
1520 else
1521 {
1522 // A wire end steps back along its wire, taking the rest along; otherwise all shift diagonally
1523 auto end = std::find_if( group.begin(), group.end(),
1524 []( const MEMBER* m )
1525 {
1526 return m->end >= 0;
1527 } );
1528
1529 bool oneEnd = std::count_if( group.begin(), group.end(),
1530 []( const MEMBER* m )
1531 {
1532 return m->end >= 0;
1533 } )
1534 == 1;
1535
1536 if( oneEnd )
1537 {
1538 auto [line, lineEnd] = endAt( *end, pos );
1539 moved = stepIn( line, lineEnd );
1540 }
1541
1542 // The diagonal step skips spots another item already holds
1543 if( moved == pos )
1544 {
1545 do
1546 {
1547 ++step;
1548 moved = pos + VECTOR2I( step * SIGNAL_GAP, step * SIGNAL_GAP );
1549 } while( !isFree( moved ) && step < MAX_DIAGONAL_STEPS );
1550 }
1551 }
1552
1553 for( const MEMBER* m : group )
1554 {
1555 if( m->end >= 0 )
1556 {
1557 auto [line, lineEnd] = endAt( m, pos );
1558 setWireEnd( line, lineEnd, moved );
1559 }
1560 else if( !m->fixed )
1561 {
1562 m->item->SetPosition( moved );
1563 }
1564 }
1565 }
1566 }
1567}
1568
1569
1570std::optional<VECTOR2I> TARGET3001_SCH_BUILDER::bendAround( int aSheet, int aSignal, const VECTOR2I& aPos,
1571 std::vector<std::pair<SCH_LINE*, int>>& aWires,
1572 const std::function<bool( const VECTOR2I& )>& aIsFree )
1573{
1574 std::vector<SCH_LINE*> lines;
1575
1576 for( const auto& [wire, signal] : aWires )
1577 {
1578 if( signal == aSignal && passesThrough( wire, aPos ) )
1579 lines.push_back( wire );
1580 }
1581
1582 if( lines.empty() )
1583 return std::nullopt;
1584
1585 VECTOR2I dir = lines[0]->GetEndPoint() - lines[0]->GetStartPoint();
1586
1587 for( SCH_LINE* line : lines )
1588 {
1589 VECTOR2I span = line->GetEndPoint() - line->GetStartPoint();
1590
1591 // The bend needs room on both sides, and the point's other items must sit on every bent line
1592 if( span.Cross( dir ) || ( aPos - line->GetStartPoint() ).EuclideanNorm() <= 2 * SIGNAL_GAP
1593 || ( line->GetEndPoint() - aPos ).EuclideanNorm() <= 2 * SIGNAL_GAP )
1594 {
1595 return std::nullopt;
1596 }
1597 }
1598
1599 VECTOR2I normal = VECTOR2I( -dir.y, dir.x ).Resize( SIGNAL_GAP );
1600 VECTOR2I side = normal;
1601
1602 for( int k : { 1, -1, 2, -2, 3, -3 } )
1603 {
1604 if( aIsFree( aPos + normal * k ) )
1605 {
1606 side = normal * k;
1607 break;
1608 }
1609 }
1610
1611 for( SCH_LINE* line : lines )
1612 {
1613 VECTOR2I along = ( line->GetEndPoint() - line->GetStartPoint() ).Resize( SIGNAL_GAP );
1614 VECTOR2I before = aPos - along;
1615 VECTOR2I after = aPos + along;
1616 VECTOR2I end = line->GetEndPoint();
1617
1618 line->SetEndPoint( before );
1619
1620 for( const auto& [from, to] : { std::pair( before, before + side ), std::pair( before + side, after + side ),
1621 std::pair( after + side, after ), std::pair( after, end ) } )
1622 {
1623 SCH_LINE* piece = new SCH_LINE( *line );
1624 piece->SetStartPoint( from );
1625 piece->SetEndPoint( to );
1626 addNetItem( aSheet, piece, aSignal );
1627 aWires.emplace_back( piece, aSignal );
1628 }
1629 }
1630
1631 return side;
1632}
1633
1634
1636{
1637 int sheet = sheetOf( aElem );
1638
1639 if( sheet == 0 )
1640 return;
1641
1642 if( aElem.type == ELEMENT_TYPE::SYMBOL && aElem.symbol )
1643 {
1644 addFreeSymbol( aElem );
1645 return;
1646 }
1647
1648 addToSheet( sheet, makeGraphic( aElem, VECTOR2I( 0, 0 ), false ) );
1649}
1650
1651
1653{
1654 // A symbol without a component draws its placeholder texts as stored and is not a part
1655 wxString reference = wxString::Format( wxS( "#SYM%d" ), ++m_freeSymbolCount );
1656 wxString symName = LIB_ID::FixIllegalChars( reference.Mid( 1 ), false ).wx_str();
1657
1658 LIB_SYMBOL lib( symName );
1659 lib.SetLibId( LIB_ID( LIB_NAME, symName ) );
1660 lib.GetReferenceField().SetText( reference );
1661 addGateBodies( &lib, { &aSymbol }, false );
1662
1664 path.push_back( m_sheets.at( sheetOf( aSymbol ) ) );
1665
1666 SCH_SYMBOL* symbol = new SCH_SYMBOL( lib, lib.GetLibId(), &path, 1, 0, toSch( aSymbol.base.x, aSymbol.base.y ) );
1667 symbol->SetLibSymbol( new LIB_SYMBOL( lib ) );
1668 symbol->SetRef( &path, reference );
1669 symbol->GetField( FIELD_T::REFERENCE )->SetVisible( false );
1670 symbol->GetField( FIELD_T::VALUE )->SetVisible( false );
1671 symbol->SetExcludedFromBOM( true );
1672 symbol->SetExcludedFromBoard( true );
1673 symbol->SetExcludedFromSim( true );
1674 addToSheet( sheetOf( aSymbol ), symbol );
1675
1676 for( const ELEMENT& child : aSymbol.symbol->children )
1677 {
1678 if( SCH_BITMAP* picture = makePicture( child ) )
1679 addToSheet( sheetOf( aSymbol ), picture );
1680 }
1681}
1682
1683
1685{
1686 auto it = m_sheets.find( aSheet );
1687
1688 if( it != m_sheets.end() )
1689 return it->second->GetScreen();
1690
1691 SCH_SHEET* sheet;
1692
1693 // The first sheet in use holds its content in the root sheet
1694 if( m_sheets.empty() )
1695 {
1696 sheet = m_rootSheet;
1697 }
1698 else
1699 {
1700 sheet = new SCH_SHEET( &m_schematic->Root() );
1701 SCH_SCREEN* newScreen = new SCH_SCREEN( m_schematic );
1702
1703 wxFileName fn( m_fileName );
1704 fn.SetName( fn.GetName() + wxString::Format( wxS( "_%d" ), aSheet ) );
1706
1707 newScreen->SetFileName( fn.GetFullPath() );
1708 sheet->SetScreen( newScreen );
1709 sheet->SetFileName( fn.GetFullName() );
1710 }
1711
1712 wxString name;
1713
1714 if( aSheet - 1 < int( m_project.settings.sheetNames.size() ) )
1715 name = ToWx( m_project.settings.sheetNames[aSheet - 1] );
1716
1717 if( name.IsEmpty() )
1718 name = wxString::Format( wxS( "Sheet %d" ), aSheet );
1719
1720 if( sheet != m_rootSheet )
1721 sheet->SetName( name );
1722
1723 m_sheets[aSheet] = sheet;
1724 return sheet->GetScreen();
1725}
1726
1727
1729{
1730 const int margin = schIUScale.mmToIU( PAGE_MARGIN_MM );
1731
1732 for( auto& [sheet, items] : m_pending )
1733 {
1734 SCH_SCREEN* scr = screen( sheet );
1735 BOX2I extent = m_extents[sheet];
1736
1737 // Target sheets are centred on their origin; KiCad pages start at the top left corner
1738 auto snap = []( int v )
1739 {
1740 return KiROUND( double( v ) / PLACEMENT_GRID ) * PLACEMENT_GRID;
1741 };
1742
1743 VECTOR2I offset( snap( margin - extent.GetLeft() ), snap( margin - extent.GetTop() ) );
1744
1746 page.SetWidthMM( std::max( 297.0, schIUScale.IUTomm( extent.GetWidth() + 2 * margin ) ) );
1747 page.SetHeightMM( std::max( 210.0, schIUScale.IUTomm( extent.GetHeight() + 2 * margin ) ) );
1748 scr->SetPageSettings( page );
1749
1750 for( SCH_ITEM* item : items )
1751 {
1752 item->Move( offset );
1753 scr->Append( item );
1754 }
1755 }
1756
1757 if( m_sheets.size() > 1 )
1758 {
1759 std::vector<SCH_SHEET*> sheets;
1760
1761 for( const auto& [number, sheet] : m_sheets )
1762 sheets.push_back( sheet );
1763
1764 m_schematic->SetTopLevelSheets( sheets );
1765 }
1766
1767 int page = 1;
1768
1769 for( const auto& [number, sheet] : m_sheets )
1770 sheet->GetScreen()->SetPageNumber( wxString::Format( wxS( "%d" ), page++ ) );
1771}
int index
const char * name
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:130
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
void SetImageType(wxBitmapType aType)
Set the bitmap type (png, jpeg, etc.)
constexpr size_type GetWidth() const
Definition box2.h:211
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:594
constexpr size_type GetHeight() const
Definition box2.h:212
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr coord_type GetTop() const
Definition box2.h:226
bool IsZero() const
Definition eda_angle.h:135
virtual VECTOR2I GetPosition() const
Definition eda_item.h:348
virtual const BOX2I GetBoundingBox() const
Return the orthogonal bounding box of this object for display purposes.
Definition eda_item.cpp:270
KICAD_T Type() const
Returns the type of object.
Definition eda_item.h:110
virtual void SetEnd(const VECTOR2I &aEnd)
Definition eda_shape.h:337
virtual void SetCenter(const VECTOR2I &aCenter)
virtual void SetArcGeometry(const VECTOR2I &aStart, const VECTOR2I &aMid, const VECTOR2I &aEnd)
Set the three controlling points for an arc.
A mix-in class (via multiple inheritance) that handles texts such as labels, parts,...
Definition eda_text.h:94
virtual int GetTextHeight() const
Definition eda_text.h:307
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:378
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:268
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:370
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
Definition lib_id.cpp:205
Define a library symbol object.
Definition lib_symbol.h:114
const LIB_ID & GetLibId() const override
Definition lib_symbol.h:190
void SetGlobalPower()
LIB_ITEMS_CONTAINER & GetDrawItems()
Return a reference to the draw item list.
Definition lib_symbol.h:843
void SetUnitCount(int aCount, bool aDuplicateDrawItems)
Set the units per symbol count.
SCH_FIELD & GetValueField()
Definition lib_symbol.h:447
void SetLibId(const LIB_ID &aLibId)
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()
Definition lib_symbol.h:451
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:75
void SetWidthMM(double aWidthInMM)
Definition page_info.h:135
void SetHeightMM(double aHeightInMM)
Definition page_info.h:140
A REFERENCE_IMAGE is a wrapper around a BITMAP_IMAGE that is displayed in an editor as a reference fo...
BITMAP_BASE & MutableImage() const
Only use this if you really need to modify the underlying image.
void Rotate(const VECTOR2I &aCenter, const EDA_ANGLE &aAngle)
bool SetImage(const wxImage &aImage)
Set the image from an existing wxImage.
void SetPosition(const VECTOR2I &aPos)
void SetWidth(int aWidth)
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
Holds all the data relating to one schematic.
Definition schematic.h:149
Object to handle a bitmap image that can be inserted in a schematic.
Definition sch_bitmap.h:36
REFERENCE_IMAGE & GetReferenceImage()
Definition sch_bitmap.h:50
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:170
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
void SetStartPoint(const VECTOR2I &aPosition)
Definition sch_line.h:137
VECTOR2I GetEndPoint() const
Definition sch_line.h:145
VECTOR2I GetStartPoint() const
Definition sch_line.h:136
virtual void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_line.h:199
bool IsEndPoint(const VECTOR2I &aPoint) const override
Test if aPt is an end point of this schematic object.
Definition sch_line.h:88
double GetLength() const
Definition sch_line.cpp:341
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:146
void Append(SCH_ITEM *aItem, bool aUpdateLibSymbol=true)
void SetPageSettings(const PAGE_INFO &aPageSettings)
Definition sch_screen.h:145
void SetFileName(const wxString &aFileName)
Set the file name for this screen to aFileName.
void SetStroke(const STROKE_PARAMS &aStroke) override
Definition sch_shape.cpp:98
void AddPoint(const VECTOR2I &aPosition)
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition sch_sheet.h:48
void SetFileName(const wxString &aFilename)
Definition sch_sheet.h:398
void SetName(const wxString &aName)
Definition sch_sheet.h:149
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:151
void SetScreen(SCH_SCREEN *aScreen)
Set the SCH_SCREEN associated with this sheet to aScreen.
Schematic symbol object.
Definition sch_symbol.h:75
void SetExcludedFromSim(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void SetFootprintFieldText(const wxString &aFootprint)
void SetExcludedFromBOM(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
void SetLibSymbol(LIB_SYMBOL *aLibSymbol)
Set this schematic symbol library symbol reference to aLibSymbol.
void SetExcludedFromBoard(bool aEnable, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
Definition seg.h:38
VECTOR2I A
Definition seg.h:45
VECTOR2I::extended_type ecoord
Definition seg.h:40
VECTOR2I B
Definition seg.h:46
const VECTOR2I NearestPoint(const VECTOR2I &aP) const
Compute a point on the segment (this) that is closest to point aP.
Definition seg.cpp:599
static SEG::ecoord Square(int a)
Definition seg.h:119
Spin style for labels of all kinds on schematics.
Definition sch_label.h:38
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
Maps TARGET 3001!
static VECTOR2I BaselineShift(const EDA_TEXT &aText)
Offset in text units that moves aText so the baseline-left point of its first glyph lies on its posit...
void Apply(EDA_TEXT *aText, const ELEMENT &aElem, int aUnit)
Give aText the font, style, size and stroke width of text aElem.
void addNetItem(int aSheet, SCH_ITEM *aItem, int aSignal)
Add a wire, junction or label of signal aSignal; separateSignals() keeps it apart from other signals.
const TARGET3001::PROJECT & m_project
TARGET3001_SCH_BUILDER(SCHEMATIC *aSchematic, SCH_SHEET *aRootSheet, const TARGET3001::PROJECT &aProject, const wxString &aFileName, REPORTER *aReporter)
void addToSheet(int aSheet, SCH_ITEM *aItem)
void addFreeItem(const TARGET3001::ELEMENT &aElem)
bool joinsGlobally(const TARGET3001::ELEMENT &aSignal) const
True when the signal's labels must be global: it reaches several sheets or meets supply symbols.
static VECTOR2I toSch(int32_t aX, int32_t aY)
Sheet position in KiCad units, before the per-sheet page offset is applied.
std::map< int, std::vector< PIN_END > > m_pinEnds
placed pins of each signal, by signal ID
SCH_BITMAP * makePicture(const TARGET3001::ELEMENT &aElem) const
Image a rectangle shows instead of its fill, or nullptr when it has none.
std::map< int, std::set< int > > m_powerSheets
sheets holding a power symbol, by signal ID
void joinSignalPieces()
Join the pieces of every signal as separateSignals() left them; see joinPieces()
SCH_ITEM * makeGraphic(const TARGET3001::ELEMENT &aElem, const VECTOR2I &aOrigin, bool aInSymbol) const
Add graphics shared by free items and symbol bodies; returns nullptr for unsupported items.
std::map< int, BOX2I > m_extents
drawn extent of each sheet
void addFreeSymbol(const TARGET3001::ELEMENT &aSymbol)
void joinPieces(int aSignal, const std::map< int, std::vector< SCH_ITEM * > > &aItems)
Join the pieces of signal aSignal that KiCad would see apart, since the file joins a signal's items b...
std::map< int, std::vector< std::pair< SCH_ITEM *, int > > > m_netItems
items and their signal, by sheet
std::map< int, std::vector< std::pair< VECTOR2I, int > > > m_pinSignals
pin points and signal, by sheet
TARGET3001::FONTS m_fonts
lookup cache, filled while drawing
std::optional< VECTOR2I > labelAnchor(const TARGET3001::ELEMENT &aSignal, int aSheet, const VECTOR2I &aPos) const
Point on the signal's own wires or pins nearest a name drawn at aPos, if it is close enough to name t...
std::optional< VECTOR2I > bendAround(int aSheet, int aSignal, const VECTOR2I &aPos, std::vector< std::pair< SCH_LINE *, int > > &aWires, const std::function< bool(const VECTOR2I &)> &aIsFree)
Bend the wires of aSignal that pass through aPos around it, one gap aside on a side aIsFree accepts,...
void addGateBodies(LIB_SYMBOL *aLib, const std::vector< const TARGET3001::ELEMENT * > &aGates, bool aFieldTexts, const std::map< uint16_t, wxString > &aPadNumbers={}) const
Draw each gate's body as one unit of aLib; aFieldTexts leaves reference and value texts to fields.
void addComponent(const TARGET3001::ELEMENT &aComponent)
void addConnections(const TARGET3001::ELEMENT &aSignal)
std::map< int, std::vector< SCH_ITEM * > > m_pending
std::set< int > m_globalSignals
signals joined by global labels
void separateSignals(int aSheet)
Move apart items of different signals that touch where KiCad would join them, since the file connects...
SCH_SCREEN * screen(int aSheet)
Screen for a 1-based sheet number, created on first use.
std::map< int, SCH_SHEET * > m_sheets
by 1-based sheet number
static int sheetOf(const TARGET3001::ELEMENT &aElem)
Sheet number of a schematic element, or 0 for board elements.
wxString wx_str() const
Definition utf8.cpp:41
constexpr extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition vector2d.h:559
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:281
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
Definition vector2d.h:567
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:406
@ DEGREES_T
Definition eda_angle.h:30
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:445
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:444
@ FILLED_SHAPE
Fill with object color.
Definition eda_fill.h:31
static const std::string KiCadSchematicFileExtension
SCH_LAYER_ID
Eeschema drawing layers.
Definition layer_ids.h:477
@ LAYER_DEVICE
Definition layer_ids.h:494
@ LAYER_WIRE
Definition layer_ids.h:480
@ LAYER_NOTES
Definition layer_ids.h:495
@ LAYER_BUS
Definition layer_ids.h:481
constexpr double PAGE_MARGIN_MM
Margin added on every side of the drawn extents before choosing a page, in millimetres.
constexpr int SCHEMATIC_SHEET_COUNT
Sheets occupy layers 101 to 200.
wxString ToWx(const std::string &aRaw)
Convert a stored ANSI string to a wxString.
ELEMENT_TYPE
Element class tags as stored in the file.
constexpr int SCHEMATIC_LAYER_BASE
First layer number used for schematic sheets; sheet N (1-based) is layer 100 + N.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:437
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_NC
not connected (must be left open)
Definition pin_type.h:46
@ PT_OUTPUT
usual output
Definition pin_type.h:34
@ PT_TRISTATE
tri state bus pin
Definition pin_type.h:36
@ PT_NIC
not internally connected (may be connected to anything)
Definition pin_type.h:40
@ PT_BIDI
input or output (like port for a microprocessor)
Definition pin_type.h:35
@ PT_OPENCOLLECTOR
pin type open collector
Definition pin_type.h:44
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
@ PT_UNSPECIFIED
unknown electrical properties: creates always a warning when connected
Definition pin_type.h:41
@ PT_PASSIVE
pin for passive symbols: must be connected, and can be connected to any pin.
Definition pin_type.h:39
PIN_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
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
LINE_STYLE
Dashed line types.
Stroked arc or circle. The base position is the start point.
double Sweep() const
Counter-clockwise sweep in (0, 360]; equal angles give a full circle.
float startAngle
degrees, counter-clockwise from +X
Fields shared by every drawable element.
std::vector< uint8_t > Picture() const
Encoded image a rectangle shows stretched over its area instead of its fill, empty for none.
uint16_t component
ID of the owning component (a component stores its own), 0 for none.
uint16_t signal
ID of the owning signal (a signal stores its own), 0 for none.
std::optional< std::pair< int32_t, int32_t > > TextRightEnd() const
Right end of right-aligned text from its ARXY property, in file coordinates.
const std::string * FindProp(const std::string &aKey) const
Return the value of the first property named aKey, if any.
One element of any class.
std::shared_ptr< COMPONENT > component
std::shared_ptr< SYMBOL > symbol
std::shared_ptr< SIGNAL > signal
std::vector< ELEMENT > children
Children of a pin (its number text).
uint8_t dashStyle
0 solid, 1 long dash, 2 dash-dot, 3 other, 4 short dash
Schematic pin. The base position is the connection point; the pin extends along direction.
Filled rectangle anchored at a corner (the base position); sizes are signed.
Filled triangle given by three absolute corners (the first is the base position).
wxString ToWx(const std::string &aRaw)
Convert a stored ANSI string to a wxString.
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
bool moved
std::string path
KIBIS_COMPONENT * comp
KIBIS_PIN * pin
VECTOR2I center
int radius
VECTOR2I end
static double sweep(float aStart, float aEnd)
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_BOTTOM
@ 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:227
bool IsPointOnSegment(const VECTOR2I &aSegStart, const VECTOR2I &aSegEnd, const VECTOR2I &aTestPoint)
Test if aTestPoint is on line defined by aSegStart and aSegEnd.
Definition trigo.cpp:87
double DEG2RAD(double deg)
Definition trigo.h:172
@ SCH_LINE_T
Definition typeinfo.h:159
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
Definition of file extensions used in Kicad.