KiCad PCB EDA Suite
Loading...
Searching...
No Matches
easypc_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
22
23#include <algorithm>
24#include <climits>
25#include <cmath>
26#include <numeric>
27#include <utility>
28
39
40#include <bus_alias.h>
41#include <geometry/seg.h>
42#include <lib_id.h>
43#include <lib_symbol.h>
44#include <page_info.h>
45#include <reporter.h>
46#include <sch_bus_entry.h>
47#include <sch_junction.h>
48#include <sch_label.h>
49#include <sch_line.h>
50#include <sch_no_connect.h>
51#include <sch_pin.h>
52#include <sch_screen.h>
53#include <sch_shape.h>
54#include <sch_sheet.h>
55#include <sch_sheet_path.h>
56#include <sch_symbol.h>
57#include <sch_text.h>
58#include <schematic.h>
59#include <string_utils.h>
60#include <transform.h>
61
62#include <wx/regex.h>
63
64
65namespace EASYPC
66{
67
69static constexpr int32_t SHEET_ORIGIN_GRID = 25400;
70
71static constexpr int32_t PAGE_MARGIN = static_cast<int32_t>( PAGE_MARGIN_MM * 10000 );
72
74static constexpr int32_t DETOUR = 10;
75
76
77bool IsNamedNet( const wxString& aName )
78{
79 // Automatic names are N or n and digits, optionally with a "!sheet!" suffix
80 static wxRegEx automatic( wxS( "^[Nn][0-9]+(![^!]*!)?$" ), wxRE_ADVANCED );
81
82 return !automatic.Matches( aName );
83}
84
85
87{
88 std::set<wxString> names;
89
90 for( const std::unique_ptr<OBJECT>& obj : aDoc.Objects )
91 {
92 const SOURCE_NET* net = dynamic_cast<const SOURCE_NET*>( obj.get() );
93
94 if( net && IsNamedNet( net->Name ) )
95 {
96 m_canonical.emplace( net->Name.Upper(), net->Name );
97 names.insert( net->Name.Upper() );
98 }
99 }
100
101 for( const wxString& name : names )
103}
104
105
106bool SCH_NET_NAMES::Shared( const wxString& aName ) const
107{
108 auto it = m_sheetCount.find( aName.Upper() );
109 return IsNamedNet( aName ) && it != m_sheetCount.end() && it->second > 1;
110}
111
112
113wxString SCH_NET_NAMES::Name( const wxString& aStoredName ) const
114{
115 auto it = m_canonical.find( aStoredName.Upper() );
116 return !IsNamedNet( aStoredName ) || it == m_canonical.end() ? aStoredName : it->second;
117}
118
119
121static POINT32 placePoint( const SOURCE_SYMBOL_INSTANCE& aInst, const SOURCE_SYMBOL& aSym, const POINT32& aLocal )
122{
123 int64_t x = static_cast<int64_t>( aLocal.X ) - aSym.OriginX;
124 int64_t y = static_cast<int64_t>( aLocal.Y ) - aSym.OriginY;
125 int32_t rx = 0;
126 int32_t ry = 0;
127
128 if( aInst.Mirrored )
129 x = -x;
130
131 // A rotated offset keeps its length, which must fit the file's 32-bit coordinates
132 if( std::hypot( static_cast<double>( x ), static_cast<double>( y ) ) > INT32_MAX )
133 THROW_IO_ERROR( wxString::Format( _( "Easy-PC symbol %s has a point too far from its origin" ), aSym.Name ) );
134
135 PointRotate( static_cast<double>( x ), static_cast<double>( y ), aInst.Angle, 0.0, 0.0, rx, ry );
136
137 int64_t px = static_cast<int64_t>( aInst.Position.X ) + rx;
138 int64_t py = static_cast<int64_t>( aInst.Position.Y ) + ry;
139
140 if( px < INT32_MIN || px > INT32_MAX || py < INT32_MIN || py > INT32_MAX )
141 THROW_IO_ERROR( wxString::Format( _( "Easy-PC symbol %s has a point outside the design" ), aSym.Name ) );
142
143 return POINT32{ static_cast<int32_t>( px ), static_cast<int32_t>( py ) };
144}
145
146
148static bool isDrawn( const SOURCE_SYMBOL_INSTANCE& aInst )
149{
150 if( aInst.Placed )
151 return true;
152
154 {
155 if( pad->Node )
156 return true;
157 }
158
159 return false;
160}
161
162
163static const SOURCE_NET* netOf( const OBJECT* aNode )
164{
165 const SOURCE_NODE* node = dynamic_cast<const SOURCE_NODE*>( aNode );
166 return node ? dynamic_cast<const SOURCE_NET*>( node->Parent ) : nullptr;
167}
168
169
170static const SOURCE_TEXT_STYLE* defaultTextStyle( const SOURCE_DESIGN& aDesign )
171{
172 return aDesign.Defaults ? dynamic_cast<const SOURCE_TEXT_STYLE*>( aDesign.Defaults->TextStyle ) : nullptr;
173}
174
175
177static std::vector<const SOURCE_ATTRIBUTE*> partAttributes( const SOURCE_COMPONENT_INSTANCE& aComp,
178 const SOURCE_COMPONENT& aPart )
179{
180 std::vector<const SOURCE_ATTRIBUTE*> out;
181 std::vector<SOURCE_ATTRIBUTE*> own = TypedItems<SOURCE_ATTRIBUTE>( aComp.Attributes );
182
183 for( SOURCE_ATTRIBUTE* attr : TypedItems<SOURCE_ATTRIBUTE>( aPart.Board ? aPart.Board->Attributes : nullptr ) )
184 {
185 auto over = std::find_if( own.begin(), own.end(),
186 [&]( const SOURCE_ATTRIBUTE* aMine )
187 {
188 return aMine->AttributeName && attr->AttributeName
189 && aMine->AttributeName->Name.CmpNoCase( attr->AttributeName->Name ) == 0;
190 } );
191
192 out.push_back( over != own.end() ? *over : attr );
193 }
194
195 for( const SOURCE_ATTRIBUTE* mine : own )
196 {
197 if( std::find( out.begin(), out.end(), mine ) == out.end() )
198 out.push_back( mine );
199 }
200
201 return out;
202}
203
204
206static wxString attributeValue( const SOURCE_COMPONENT_INSTANCE& aComp, const SOURCE_COMPONENT& aPart,
207 const wxString& aName )
208{
209 for( const SOURCE_ATTRIBUTE* attr : partAttributes( aComp, aPart ) )
210 {
211 if( attr->AttributeName && attr->AttributeName->Name.CmpNoCase( aName ) == 0 )
212 return attr->Value;
213 }
214
215 return wxEmptyString;
216}
217
218
221{
223 wxString Name;
224 wxString Text;
225};
226
227
228static std::vector<VALUE_LINE> valueLines( const SOURCE_VALUE_POSITION& aVp, const SOURCE_COMPONENT_INSTANCE& aComp,
229 const SOURCE_COMPONENT& aPart, const SOURCE_SYMBOL_INSTANCE& aInst )
230{
231 std::vector<VALUE_LINE> lines;
232 uint64_t shown = aVp.Types & aComp.ValueTypes;
233 const SOURCE_SYMBOL* sym = dynamic_cast<const SOURCE_SYMBOL*>( aInst.Symbol );
234
235 auto add = [&]( FIELD_T aField, const wxString& aName, const wxString& aText )
236 {
237 if( !aText.IsEmpty() )
238 lines.push_back( { aField, aName, aText } );
239 };
240
241 if( shown & VALUE_REFERENCE_NAME )
242 add( FIELD_T::REFERENCE, wxEmptyString, aComp.Name );
243
244 if( shown & VALUE_COMPONENT_NAME )
245 add( FIELD_T::USER, wxS( "Component" ), aPart.Schematic ? aPart.Schematic->Name : wxString() );
246
247 if( shown & VALUE_PACKAGE_NAME )
248 add( FIELD_T::USER, wxS( "Package" ), aPart.Board ? aPart.Board->Package : wxString() );
249
250 if( shown & VALUE_SYMBOL_NAME )
251 add( FIELD_T::USER, wxS( "Symbol" ), sym ? sym->Name : wxString() );
252
253 if( shown & VALUE_DESCRIPTION )
254 add( FIELD_T::USER, wxS( "Description" ), aPart.Schematic ? aPart.Schematic->Description : wxString() );
255
256 // Values is not masked by the part's value types; each displayed attribute adds its value
257 for( uint64_t kind : { VALUE_VALUES, VALUE_ATTRIBUTE } )
258 {
259 if( !( aVp.Types & kind ) )
260 continue;
261
262 for( const SOURCE_ATTRIBUTE* attr : partAttributes( aComp, aPart ) )
263 {
264 if( !attr->AttributeName
265 || ( kind == VALUE_VALUES ? !attr->Displayed
266 : attr->AttributeName->Name.CmpNoCase( aVp.Attribute ) != 0 ) )
267 {
268 continue;
269 }
270
271 bool isValue = attr->AttributeName->Name.CmpNoCase( wxS( "Value" ) ) == 0;
272 add( isValue ? FIELD_T::VALUE : FIELD_T::USER, attr->AttributeName->Name, attr->Value );
273 }
274 }
275
276 return lines;
277}
278
279
280static wxString joinLines( const std::vector<VALUE_LINE>& aLines )
281{
282 wxString whole;
283
284 for( const VALUE_LINE& line : aLines )
285 whole += ( whole.IsEmpty() ? wxString() : wxString( wxS( "\n" ) ) ) + line.Text;
286
287 return whole;
288}
289
290
291SCH_BUILDER::SCH_BUILDER( SCHEMATIC* aSchematic, const SCH_NET_NAMES& aNames, REPORTER* aReporter ) :
292 m_schematic( aSchematic ),
293 m_names( aNames ),
294 m_reporter( aReporter )
295{
296}
297
298
299void SCH_BUILDER::SetProjectSymbols( const std::vector<const DESIGN_DOCUMENT*>& aDocs )
300{
301 m_projectSymbols.clear();
302
303 for( const DESIGN_DOCUMENT* doc : aDocs )
304 {
305 for( SOURCE_SYMBOL* sym :
306 TypedItems<SOURCE_SYMBOL>( static_cast<const SOURCE_DESIGN&>( *doc->Design ).Symbols ) )
307 m_projectSymbols.emplace( sym->Name, sym );
308 }
309}
310
311
312VECTOR2I SCH_BUILDER::toSheet( int32_t aX, int32_t aY ) const
313{
314 return SCH_FRAME{ m_originX, m_originY }.Map( aX, aY );
315}
316
317
319{
320 return toSheet( aPoint.X, aPoint.Y );
321}
322
323
324static int32_t floorTo( int64_t aValue, int32_t aGrid )
325{
326 int64_t q = aValue / aGrid;
327
328 if( aValue % aGrid < 0 )
329 q--;
330
331 return static_cast<int32_t>( q * aGrid );
332}
333
334
336{
337 // A design's stored area is usually unbounded, so the page is fitted to the drawing
338 int64_t minX = INT64_MAX, minY = INT64_MAX, maxX = INT64_MIN, maxY = INT64_MIN;
339
340 auto add = [&]( int64_t aX, int64_t aY )
341 {
342 minX = std::min( minX, aX );
343 minY = std::min( minY, aY );
344 maxX = std::max( maxX, aX );
345 maxY = std::max( maxY, aY );
346 };
347
348 auto addShape = [&]( const OBJECT* aShape )
349 {
350 if( const SOURCE_SHAPE* shape = dynamic_cast<const SOURCE_SHAPE*>( aShape ) )
351 {
352 for( const SOURCE_SEGMENT* seg : ShapeVertices( *shape ) )
353 add( seg->X, seg->Y );
354 }
355 };
356
357 // Texts reach past the items they belong to
358 auto addText = [&]( const SOURCE_TEXT_POSITION& aPos, const wxString& aText )
359 {
360 const SOURCE_TEXT_STYLE* style = dynamic_cast<const SOURCE_TEXT_STYLE*>( aPos.TextStyle );
361
362 if( !style || aText.IsEmpty() || !TEXT_METRICS( *style ).CanMeasure() )
363 return;
364
365 BOX2I box = TEXT_METRICS( *style ).TextBox( aText, VECTOR2I( aPos.Position.X, aPos.Position.Y ), aPos.Rotation,
366 aPos.Mirrored, aPos.Alignment );
367 add( box.GetLeft(), box.GetTop() );
368 add( box.GetRight(), box.GetBottom() );
369 };
370
371 for( SOURCE_NET* net : TypedItems<SOURCE_NET>( aDesign.Nets ) )
372 {
373 for( SOURCE_NODE* node : TypedItems<SOURCE_NODE>( net->Nodes ) )
374 {
375 const SOURCE_NET_NAME* name = dynamic_cast<const SOURCE_NET_NAME*>( node->NetName );
376
377 add( node->Position.X, node->Position.Y );
378
379 if( name && name->Displayed )
380 addText( *name, net->Name );
381 }
382
383 for( SOURCE_CONNECTION* conn : TypedItems<SOURCE_CONNECTION>( net->Connections ) )
384 addShape( conn->Track );
385 }
386
388 {
389 const SOURCE_COMPONENT* part = dynamic_cast<const SOURCE_COMPONENT*>( comp->Component );
390
391 for( SOURCE_SYMBOL_INSTANCE* inst : TypedItems<SOURCE_SYMBOL_INSTANCE>( comp->SymbolInstances ) )
392 {
393 const SOURCE_SYMBOL* sym = dynamic_cast<const SOURCE_SYMBOL*>( inst->Symbol );
394
395 if( !isDrawn( *inst ) )
396 continue;
397
398 add( inst->Position.X, inst->Position.Y );
399
400 // A drawing frame is a symbol whose outline reaches far from its origin
401 for( SOURCE_FREE_COPPER* copper : TypedItems<SOURCE_FREE_COPPER>( sym ? sym->Shapes : nullptr ) )
402 {
403 if( const SOURCE_SHAPE* shape = dynamic_cast<const SOURCE_SHAPE*>( copper->Shape ) )
404 {
405 for( const SOURCE_SEGMENT* seg : ShapeVertices( *shape ) )
406 {
407 POINT32 p = placePoint( *inst, *sym, POINT32{ seg->X, seg->Y } );
408 add( p.X, p.Y );
409 }
410 }
411 }
412
413 for( SOURCE_FREE_TEXT* text : TypedItems<SOURCE_FREE_TEXT>( sym ? sym->Texts : nullptr ) )
414 {
415 POINT32 p = placePoint( *inst, *sym, text->Position );
416 add( p.X, p.Y );
417 }
418
419 for( SOURCE_VALUE_POSITION* vp :
420 TypedItems<SOURCE_VALUE_POSITION>( part ? inst->ValuePositions : nullptr ) )
421 {
422 if( vp->Displayed )
423 addText( *vp, joinLines( valueLines( *vp, *comp, *part, *inst ) ) );
424 }
425 }
426 }
427
429 {
430 add( text->Position.X, text->Position.Y );
431 addText( *text, text->Text );
432 }
433
435 addShape( copper->Shape );
436
437 for( SOURCE_BUS* bus : TypedItems<SOURCE_BUS>( aDesign.Buses ) )
438 {
439 addShape( bus->Shape );
440
441 for( SOURCE_BUS_TERMINAL* term : TypedItems<SOURCE_BUS_TERMINAL>( bus->Terminals ) )
442 {
443 add( term->Position.X, term->Position.Y );
444 add( term->BusEndPosition.X, term->BusEndPosition.Y );
445 }
446 }
447
448 if( minX > maxX )
449 minX = maxX = minY = maxY = 0;
450
453
454 // The grown extents start at the sheet origin, so the page holds the grid rounding as well
455 BOX2L extents( VECTOR2L( ( m_originX + PAGE_MARGIN ) * 100LL, minY * 100LL ),
456 VECTOR2L( ( maxX - m_originX - PAGE_MARGIN ) * 100LL, ( m_originY - PAGE_MARGIN - minY ) * 100LL ) );
457
458 m_screen->SetPageSettings( PageForExtents( extents ) );
459}
460
461
462void SCH_BUILDER::BuildSheet( const DESIGN_DOCUMENT& aDoc, SCH_SHEET* aSheet, const SCH_SHEET_PATH& aSheetPath )
463{
464 const SOURCE_DESIGN& design = static_cast<const SOURCE_DESIGN&>( *aDoc.Design );
465
466 m_screen = aSheet->GetScreen();
467 m_design = &design;
468 m_powerNodes.clear();
469 m_powerNets.clear();
470 m_labelledNets.clear();
471
472 computeOffset( design );
473 m_keepUpright = TextStaysUpright( design, true );
474
475 TITLE_BLOCK titleBlock;
476 FillTitleBlock( aDoc, titleBlock );
477 m_screen->SetTitleBlock( titleBlock );
478
479 buildSymbols( design, aSheetPath );
480 buildWires( design );
481 buildLabels( design );
482 buildCommonPinCopies( design );
483 buildBuses( design );
484
485 SCH_FRAME frame{ m_originX, m_originY };
486
488 m_screen->Append( ConvertFreeText( *text, frame, LAYER_NOTES, 0, m_keepUpright ).release() );
489
491 {
492 for( std::unique_ptr<SCH_SHAPE>& shape : ConvertShapeItem( *copper, frame, LAYER_NOTES ) )
493 m_screen->Append( shape.release() );
494 }
495}
496
497
499static TRANSFORM placementTransform( int32_t aAngle, bool aMirrored )
500{
501 int32_t angle = NormalizeAngle( aAngle );
502 int c = angle == 180000 ? -1 : ( angle == 90000 || angle == 270000 ? 0 : 1 );
503 int s = angle == 90000 ? 1 : ( angle == 270000 ? -1 : 0 );
504
505 // Library items are Y down, so the anticlockwise rotation becomes R(-angle) and the mirror keeps its sign
506 return aMirrored ? TRANSFORM( -c, s, s, c ) : TRANSFORM( c, s, -s, c );
507}
508
509
511static bool isScmOnly( const SOURCE_COMPONENT& aPart )
512{
513 if( !aPart.Board || aPart.Board->Package.IsEmpty() )
514 return true;
515
517 {
518 for( SOURCE_GATE_PIN* pin : TypedItems<SOURCE_GATE_PIN>( map->Pins ) )
519 {
520 if( !pin->PcbSymbolPin.IsEmpty() && pin->PcbSymbolPin != wxS( "-1" ) )
521 return false;
522 }
523
524 for( int32_t pad : map->PcbSymbolPins )
525 {
526 if( pad != -1 )
527 return false;
528 }
529 }
530
531 return true;
532}
533
534
535void SCH_BUILDER::buildSymbols( const SOURCE_DESIGN& aDesign, const SCH_SHEET_PATH& aSheetPath )
536{
537 SCH_FRAME frame{ m_originX, m_originY };
538 std::map<wxString, const SOURCE_COMPONENT*> libNames;
539 std::map<wxString, const SOURCE_SYMBOL*> designSymbols;
540
541 // The first symbol of each name wins, as a front-to-back search would find it
542 for( SOURCE_SYMBOL* sym : TypedItems<SOURCE_SYMBOL>( aDesign.Symbols ) )
543 designSymbols.emplace( sym->Name, sym );
544
546 {
547 const SOURCE_COMPONENT* part = dynamic_cast<const SOURCE_COMPONENT*>( comp->Component );
548
549 if( !part || !part->Schematic )
550 THROW_IO_ERROR( wxString::Format( _( "Component instance %s has no schematic component" ), comp->Name ) );
551
552 std::vector<SOURCE_SYMBOL_INSTANCE*> instances = TypedItems<SOURCE_SYMBOL_INSTANCE>( comp->SymbolInstances );
553 std::vector<SOURCE_GATE*> gates = TypedItems<SOURCE_GATE>( part->Schematic->Gates );
555
556 source.Schematic = part->Schematic;
557 source.Board = part->Board;
558 source.PinTexts = false;
559 source.Gates.assign( gates.size(), nullptr );
560
561 if( part->Board && !part->Board->Symbol.IsEmpty() )
562 source.Footprint = part->Board->Symbol;
563
564 for( SOURCE_SYMBOL_INSTANCE* inst : instances )
565 {
566 if( inst->Gate >= 0 && inst->Gate < static_cast<int>( gates.size() ) )
567 source.Gates[inst->Gate] = dynamic_cast<const SOURCE_SYMBOL*>( inst->Symbol );
568 }
569
570 // A gate not placed here is drawn from this design's symbol of the gate's name, else another sheet's
571 for( size_t g = 0; g < gates.size(); ++g )
572 {
573 if( source.Gates[g] )
574 continue;
575
576 if( auto it = designSymbols.find( gates[g]->Symbol ); it != designSymbols.end() )
577 source.Gates[g] = it->second;
578 else if( auto pit = m_projectSymbols.find( gates[g]->Symbol ); pit != m_projectSymbols.end() )
579 source.Gates[g] = pit->second;
580 }
581
582 int pinCount = 0;
583 const SOURCE_NET* signalNet = nullptr;
584
585 for( SOURCE_SYMBOL_INSTANCE* inst : instances )
586 {
588 {
589 pinCount++;
590
591 if( dynamic_cast<const SOURCE_NODE*>( pad->Node ) )
592 signalNet = netOf( pad->Node );
593 }
594 }
595
596 bool scmOnly = isScmOnly( *part );
597
598 // A schematic-only single gate with at most one pin is a signal symbol naming its net
599 bool power = scmOnly && gates.size() == 1 && pinCount < 2 && signalNet && IsNamedNet( signalNet->Name );
600
601 wxString netName = power ? m_names.Name( signalNet->Name ) : wxString();
602 wxString libName = power ? netName : part->Schematic->Name;
603 wxString base = libName;
604
605 // Different parts may share a component name or a power net in one design; each keeps its own symbol
606 for( int n = 2; libNames.count( libName ) && libNames[libName] != part; ++n )
607 libName = wxString::Format( wxS( "%s_%d" ), base, n );
608
609 libNames[libName] = part;
610
611 LIB_ID libId( wxS( "easypc" ), EscapeString( libName, CTX_LIBID ) );
612 std::unique_ptr<LIB_SYMBOL> libSymbol = ConvertComponentSymbol( source, libId );
613
614 if( power )
615 {
616 libSymbol->SetGlobalPower();
617
618 for( SOURCE_SYMBOL_INSTANCE* inst : instances )
619 {
621 {
622 if( const SOURCE_NODE* node = dynamic_cast<const SOURCE_NODE*>( pad->Node ) )
623 {
624 m_powerNodes.insert( node );
625 m_powerNets.insert( netName.Upper() );
626 }
627 }
628 }
629
630 libSymbol->GetValueField().SetText( ToKiCadMarkup( netName ) );
631
632 // KiCad names a net from a power symbol only through a power input pin
633 for( SCH_PIN* pin : libSymbol->GetGraphicalPins( 0, 0 ) )
634 {
636 pin->SetName( ToKiCadMarkup( netName ) );
637 }
638 }
639
640 for( SOURCE_SYMBOL_INSTANCE* inst : instances )
641 {
642 // KiCad has no unplaced unit; a gate whose pins are still on nets is drawn where it is stored
643 if( !isDrawn( *inst ) )
644 continue;
645
646 if( !inst->Placed )
647 {
648 m_reporter->Report( wxString::Format( _( "Unplaced gate %d of %s has connected pins and is placed "
649 "at its stored position" ),
650 inst->Gate + 1, comp->Name ),
652 }
653
654 int unit = inst->Gate >= 0 ? inst->Gate + 1 : 1;
655 SCH_SYMBOL* symbol = new SCH_SYMBOL( *libSymbol, libId, &aSheetPath, unit, 0, toSheet( inst->Position ) );
656 wxString ref = power ? wxString::Format( wxS( "#PWR%04d" ), ++m_powerCount ) : comp->Name;
657 wxString value = power ? netName : attributeValue( *comp, *part, wxS( "Value" ) );
658
659 symbol->SetLibSymbol( new LIB_SYMBOL( *libSymbol ) );
660 symbol->SetTransform( placementTransform( inst->Angle, inst->Mirrored ) );
661 symbol->GetField( FIELD_T::REFERENCE )->SetText( ref );
662 symbol->SetRef( &aSheetPath, ref );
663 symbol->SetValueFieldText( ToKiCadMarkup( power || !value.IsEmpty() ? value : part->Schematic->Name ) );
664
665 if( scmOnly || ( comp->Suppress & SUPPRESS_SCM_PCB_TRANSLATION ) )
666 symbol->SetExcludedFromBoard( true );
667
668 if( scmOnly || ( comp->Suppress & SUPPRESS_PARTS_LIST ) )
669 symbol->SetExcludedFromBOM( true );
670
671 placeFields( *symbol, *comp, *inst, power, frame );
672 m_screen->Append( symbol );
673 placePinItems( *part, *inst, frame );
674 }
675 }
676}
677
678
681 const SOURCE_TEXT_POSITION& aLocal )
682{
684 out.TextStyle = aLocal.TextStyle;
685 out.Alignment = aLocal.Alignment;
686 out.Position = placePoint( aInst, aSym, aLocal.Position );
687 out.Mirrored = aLocal.Mirrored != aInst.Mirrored;
688 out.Rotation = NormalizeAngle( ( aInst.Mirrored ? -aLocal.Rotation : aLocal.Rotation ) + aInst.Angle );
689 return out;
690}
691
692
694 const SCH_FRAME& aFrame )
695{
696 const SOURCE_SYMBOL* sym = dynamic_cast<const SOURCE_SYMBOL*>( aInst.Symbol );
697 std::vector<SOURCE_GATE*> gates = TypedItems<SOURCE_GATE>( aPart.Schematic ? aPart.Schematic->Gates : nullptr );
698 const SOURCE_GATE* gate =
699 aInst.Gate >= 0 && aInst.Gate < static_cast<int>( gates.size() ) ? gates[aInst.Gate] : nullptr;
700
701 auto addText = [&]( const wxString& aText, const SOURCE_TEXT_POSITION& aPos )
702 {
703 if( aText.IsEmpty() )
704 return;
705
706 SCH_TEXT* text = new SCH_TEXT( VECTOR2I( 0, 0 ), ToKiCadMarkup( aText ), LAYER_NOTES );
707 ApplyTextPosition( *text, aPos, aFrame, m_keepUpright, aText );
708 m_screen->Append( text );
709 };
710
712 {
713 const SOURCE_FREE_PAD* freePad = dynamic_cast<const SOURCE_FREE_PAD*>( pad->Pad );
714
715 if( !freePad )
716 continue;
717
718 int terminal = freePad->Number - 1;
719 GATE_TERMINAL resolved = ResolveTerminal( aPart.Board, aInst.Gate, terminal );
720 const SOURCE_NET* net = netOf( pad->Node );
721 wxString pinName;
722
723 if( gate && terminal >= 0 && terminal < static_cast<int>( gate->PinNames.size() ) )
724 pinName = gate->PinNames[terminal];
725
726 // A no-connect gate pin left unwired; crosses on other unconnected pins are their pad style
727 if( resolved.NoConnect && !dynamic_cast<const SOURCE_NODE*>( pad->Node ) && sym )
728 m_screen->Append( new SCH_NO_CONNECT( toSheet( placePoint( aInst, *sym, freePad->Position ) ) ) );
729
730 for( SOURCE_VALUE_POSITION* vp : TypedItems<SOURCE_VALUE_POSITION>( pad->ValuePositions ) )
731 {
732 if( !vp->Displayed )
733 continue;
734
735 if( vp->Types & VALUE_PIN_NAME )
736 addText( pinName, *vp );
737 else if( vp->Types & VALUE_PIN_NUMBER )
738 addText( resolved.Display, *vp );
739 else if( ( vp->Types & VALUE_NET_NAME ) && net )
740 addText( m_names.Name( net->Name ), *vp );
741 }
742
743 // Below 10003 the pin texts are instances of the symbol's pin name and number
744 const SOURCE_PIN_NAME_INSTANCE* name = dynamic_cast<const SOURCE_PIN_NAME_INSTANCE*>( pad->PinName );
745 const SOURCE_PIN_NAME_INSTANCE* number = dynamic_cast<const SOURCE_PIN_NAME_INSTANCE*>( pad->PinNumber );
746
747 if( sym && name && name->Visible )
748 {
749 if( const SOURCE_TEXT_POSITION* def = dynamic_cast<const SOURCE_TEXT_POSITION*>( name->Definition ) )
750 addText( pinName, placedText( aInst, *sym, *def ) );
751 }
752
753 if( sym && number && number->Visible )
754 {
755 if( const SOURCE_TEXT_POSITION* def = dynamic_cast<const SOURCE_TEXT_POSITION*>( number->Definition ) )
756 addText( resolved.Display, placedText( aInst, *sym, *def ) );
757 }
758 }
759}
760
761
763 const SOURCE_SYMBOL_INSTANCE& aInst, bool aPower, const SCH_FRAME& aFrame )
764{
765 const SOURCE_COMPONENT* part = dynamic_cast<const SOURCE_COMPONENT*>( aComp.Component );
766 std::set<SCH_FIELD*> placed;
767
768 for( SCH_FIELD& field : aSymbol.GetFields() )
769 field.SetVisible( false );
770
771 for( SOURCE_VALUE_POSITION* vp : TypedItems<SOURCE_VALUE_POSITION>( part ? aInst.ValuePositions : nullptr ) )
772 {
773 if( !vp->Displayed )
774 continue;
775
776 const SOURCE_TEXT_STYLE* style = dynamic_cast<const SOURCE_TEXT_STYLE*>( vp->TextStyle );
777 int pitch = style ? style->Height * style->InterlineHeightPercent / 100 : 0;
778 std::vector<VALUE_LINE> lines = valueLines( *vp, aComp, *part, aInst );
779 wxString whole = joinLines( lines );
780
781 // Text turned upright continues downwards from its turned first line
782 int32_t drawnAngle = DrawsUpright( *vp, m_keepUpright ) ? UprightRotation( vp->Rotation, true ) : vp->Rotation;
783 double angle = drawnAngle * M_PI / 180000.0;
784 bool hasOther = std::any_of( lines.begin(), lines.end(),
785 []( const VALUE_LINE& aLine )
786 {
787 return aLine.Field != FIELD_T::REFERENCE;
788 } );
789
790 for( size_t lineIndex = 0; lineIndex < lines.size(); ++lineIndex )
791 {
792 const VALUE_LINE& line = lines[lineIndex];
793 SCH_FIELD* field = nullptr;
794
795 // A power symbol's value is drawn where its first text other than the reference is, else the reference
796 if( aPower )
797 field = line.Field != FIELD_T::REFERENCE || !hasOther ? aSymbol.GetField( FIELD_T::VALUE ) : nullptr;
798 else if( line.Field != FIELD_T::USER )
799 field = aSymbol.GetField( line.Field );
800 else if( !( field = aSymbol.GetField( line.Name ) ) )
801 field = aSymbol.AddField( SCH_FIELD( &aSymbol, FIELD_T::USER, line.Name ) );
802
803 if( !field || placed.count( field ) )
804 continue;
805
806 if( line.Field == FIELD_T::USER && !aPower )
807 field->SetText( ToKiCadMarkup( line.Text ) );
808
809 ApplyTextPosition( *field, *vp, aFrame, m_keepUpright, whole );
810
811 // Each later line sits one interline height below the first
812 VECTOR2D down( std::sin( angle ) * pitch * lineIndex, -std::cos( angle ) * pitch * lineIndex );
813 VECTOR2I pos = field->GetTextPos() + VECTOR2I( KiROUND( down.x ), KiROUND( -down.y ) );
814 GR_TEXT_H_ALIGN_T hJustify = field->GetHorizJustify();
815 GR_TEXT_V_ALIGN_T vJustify = field->GetVertJustify();
816
817 // KiCad draws a field through its symbol's transform, so store the inverse of the sheet placement
818 if( aSymbol.GetTransform().y1 )
820
821 field->SetPosition( pos );
822 field->SetEffectiveHorizJustify( hJustify );
823 field->SetEffectiveVertJustify( vJustify );
824 field->SetVisible( true );
825 placed.insert( field );
826 }
827 }
828}
829
830
832static bool collinearOverlap( const SEG& aA, const SEG& aB )
833{
834 if( aA.A == aA.B || aB.A == aB.B )
835 return false;
836
837 VECTOR2L d = VECTOR2L( aA.B - aA.A );
838
839 auto cross = [&]( const VECTOR2I& aPoint )
840 {
841 VECTOR2L r = VECTOR2L( aPoint - aA.A );
842 return d.x * r.y - d.y * r.x;
843 };
844
845 auto param = [&]( const VECTOR2I& aPoint )
846 {
847 VECTOR2L r = VECTOR2L( aPoint - aA.A );
848 return d.x * r.x + d.y * r.y;
849 };
850
851 if( cross( aB.A ) != 0 || cross( aB.B ) != 0 )
852 return false;
853
854 int64_t lo = std::max<int64_t>( 0, std::min( param( aB.A ), param( aB.B ) ) );
855 int64_t hi = std::min<int64_t>( d.x * d.x + d.y * d.y, std::max( param( aB.A ), param( aB.B ) ) );
856
857 return hi > lo;
858}
859
860
862{
863 // Every connection point with its net, null for an unconnected pin, which KiCad also connects
864 std::vector<std::pair<VECTOR2I, const SOURCE_NET*>> points;
865 std::map<VECTOR2I, std::set<const SOURCE_NET*>> netsAt;
866 std::map<int, std::vector<size_t>> pointsByX;
867 std::map<int, std::vector<size_t>> pointsByY;
868
869 for( SOURCE_NET* net : TypedItems<SOURCE_NET>( aDesign.Nets ) )
870 {
871 for( SOURCE_NODE* node : TypedItems<SOURCE_NODE>( net->Nodes ) )
872 points.emplace_back( toSheet( node->Position ), net );
873 }
874
876 {
877 for( SOURCE_SYMBOL_INSTANCE* inst : TypedItems<SOURCE_SYMBOL_INSTANCE>( comp->SymbolInstances ) )
878 {
879 const SOURCE_SYMBOL* sym = dynamic_cast<const SOURCE_SYMBOL*>( inst->Symbol );
880
882 TypedItems<SOURCE_PAD_INSTANCE>( sym && isDrawn( *inst ) ? inst->Pads : nullptr ) )
883 {
884 if( const SOURCE_FREE_PAD* freePad = dynamic_cast<const SOURCE_FREE_PAD*>( pad->Pad );
885 freePad && !pad->Node )
886 points.emplace_back( toSheet( placePoint( *inst, *sym, freePad->Position ) ), nullptr );
887 }
888 }
889 }
890
891 for( size_t i = 0; i < points.size(); ++i )
892 {
893 netsAt[points[i].first].insert( points[i].second );
894 pointsByX[points[i].first.x].push_back( i );
895 pointsByY[points[i].first.y].push_back( i );
896 }
897
898 m_sharedPoints.clear();
899
900 for( const auto& [pt, nets] : netsAt )
901 {
902 if( nets.size() > 1 )
903 m_sharedPoints.insert( pt );
904 }
905
906 // Points SEG::Contains can accept lie within one unit of the line, so an axis-aligned wire looks in three rows
907 auto candidates = [&]( const SEG& aSeg )
908 {
909 std::vector<size_t> out;
910 const std::map<int, std::vector<size_t>>* index = aSeg.A.x == aSeg.B.x ? &pointsByX
911 : aSeg.A.y == aSeg.B.y ? &pointsByY
912 : nullptr;
913 int line = index == &pointsByX ? aSeg.A.x : aSeg.A.y;
914
915 if( !index )
916 {
917 out.resize( points.size() );
918 std::iota( out.begin(), out.end(), 0 );
919 return out;
920 }
921
922 for( int c = line - 1; c <= line + 1; ++c )
923 {
924 if( auto it = index->find( c ); it != index->end() )
925 out.insert( out.end(), it->second.begin(), it->second.end() );
926 }
927
928 std::sort( out.begin(), out.end() );
929 return out;
930 };
931
932 // Spans of earlier nets by the line they lie on, for wires of two nets drawn over each other
933 using SPANS = std::vector<std::pair<SEG, int>>;
934
935 std::map<const SOURCE_NET*, int> netIndex;
936 std::map<std::pair<int, int>, SPANS> spansOnLine;
937 SPANS allSpans;
938 std::set<VECTOR2I> bareEnds;
939
940 for( SOURCE_NET* net : TypedItems<SOURCE_NET>( aDesign.Nets ) )
941 {
942 int index = static_cast<int>( netIndex.size() );
943 netIndex[net] = index;
944
945 for( SOURCE_NODE* node : TypedItems<SOURCE_NODE>( net->Nodes ) )
946 {
947 const SOURCE_JUNCTION* junction = dynamic_cast<const SOURCE_JUNCTION*>( node->Item );
948
949 // A junction without a dot is only the end or bend of a wire
950 if( junction && !junction->Style )
951 bareEnds.insert( toSheet( node->Position ) );
952 }
953
954 for( SOURCE_CONNECTION* conn : TypedItems<SOURCE_CONNECTION>( net->Connections ) )
955 {
956 const SOURCE_TRACK* track = dynamic_cast<const SOURCE_TRACK*>( conn->Track );
957 std::vector<const SOURCE_SEGMENT*> verts =
958 track ? ShapeVertices( *track ) : std::vector<const SOURCE_SEGMENT*>();
959
960 for( size_t i = 0; i + 1 < verts.size(); ++i )
961 {
962 SEG seg( toSheet( verts[i]->X, verts[i]->Y ), toSheet( verts[i + 1]->X, verts[i + 1]->Y ) );
963
964 allSpans.emplace_back( seg, index );
965
966 if( seg.A.x == seg.B.x )
967 spansOnLine[{ 0, seg.A.x }].emplace_back( seg, index );
968 else if( seg.A.y == seg.B.y )
969 spansOnLine[{ 1, seg.A.y }].emplace_back( seg, index );
970 }
971 }
972 }
973
974 auto overlapsEarlierNet = [&]( const SEG& aSeg, int aNet )
975 {
976 static const SPANS none;
977 const SPANS* spans = &allSpans;
978
979 // A span collinear with an axis-aligned one lies on its line exactly
980 if( aSeg.A.x == aSeg.B.x || aSeg.A.y == aSeg.B.y )
981 {
982 auto it = spansOnLine.find( aSeg.A.x == aSeg.B.x ? std::make_pair( 0, aSeg.A.x )
983 : std::make_pair( 1, aSeg.A.y ) );
984 spans = it == spansOnLine.end() ? &none : &it->second;
985 }
986
987 return std::any_of( spans->begin(), spans->end(),
988 [&]( const std::pair<SEG, int>& aSpan )
989 {
990 return aSpan.second < aNet && collinearOverlap( aSeg, aSpan.first );
991 } );
992 };
993
994 for( SOURCE_NET* net : TypedItems<SOURCE_NET>( aDesign.Nets ) )
995 {
996 for( SOURCE_CONNECTION* conn : TypedItems<SOURCE_CONNECTION>( net->Connections ) )
997 {
998 const SOURCE_TRACK* track = dynamic_cast<const SOURCE_TRACK*>( conn->Track );
999 std::vector<const SOURCE_SEGMENT*> verts =
1000 track ? ShapeVertices( *track ) : std::vector<const SOURCE_SEGMENT*>();
1001
1002 for( size_t i = 0; i + 1 < verts.size(); ++i )
1003 {
1004 const SOURCE_TRACK_SEGMENT* seg = dynamic_cast<const SOURCE_TRACK_SEGMENT*>( verts[i] );
1005 const SOURCE_TRACK_STYLE* style = seg ? dynamic_cast<const SOURCE_TRACK_STYLE*>( seg->Style ) : nullptr;
1006 VECTOR2I start = toSheet( verts[i]->X, verts[i]->Y );
1007 VECTOR2I end = toSheet( verts[i + 1]->X, verts[i + 1]->Y );
1008 VECTOR2D dir = VECTOR2D( end - start ).Resize( 1.0 );
1009 VECTOR2I along( KiROUND( dir.x * DETOUR ), KiROUND( dir.y * DETOUR ) );
1010 VECTOR2I across( -along.y, along.x );
1011
1012 // A bare wire end on another net's point stops short of it, since the file keeps the nets apart
1013 auto retract = [&]( VECTOR2I& aPt, const VECTOR2I& aInward, bool aIsTrackEnd )
1014 {
1015 const std::set<const SOURCE_NET*>& nets = netsAt[aPt];
1016
1017 if( !aIsTrackEnd || !bareEnds.count( aPt ) || nets.empty()
1018 || ( nets.size() == 1 && *nets.begin() == net ) )
1019 {
1020 return;
1021 }
1022
1023 wxString msg = _( "A wire of net %s ends on a connection of another net at " //format:allow
1024 "(%.4f, %.4f) mm; it stops %d nm short" ); //format:allow
1025
1026 m_reporter->Report(
1027 wxString::Format( msg, net->Name, aPt.x / 10000.0, aPt.y / 10000.0, DETOUR * 100 ),
1029 aPt += aInward;
1030 };
1031
1032 retract( start, along, i == 0 );
1033 retract( end, -along, i + 2 == verts.size() );
1034
1035 std::vector<VECTOR2I> path = { start };
1036 bool overlaps = overlapsEarlierNet( SEG( start, end ), netIndex.at( net ) );
1037
1038 // Wires of two nets drawn over each other: the later net's wire runs alongside instead
1039 if( overlaps )
1040 {
1041 m_reporter->Report( wxString::Format( _( "A wire of net %s is drawn over a wire of another "
1042 "net; it is offset by %d nm" ),
1043 net->Name, DETOUR * 100 ),
1045 path.push_back( start + across );
1046 path.push_back( end + across );
1047 }
1048
1049 // A point lying on a wire is not connected in the file, KiCad always connects it
1050 std::vector<VECTOR2I> crossings;
1051
1052 for( size_t k : overlaps ? std::vector<size_t>() : candidates( SEG( start, end ) ) )
1053 {
1054 const auto& [pt, other] = points[k];
1055
1056 if( other != net && pt != start && pt != end && SEG( start, end ).Contains( pt ) )
1057 crossings.push_back( pt );
1058 }
1059
1060 std::sort( crossings.begin(), crossings.end(),
1061 [&]( const VECTOR2I& l, const VECTOR2I& r )
1062 {
1063 return ( l - start ).SquaredEuclideanNorm() < ( r - start ).SquaredEuclideanNorm();
1064 } );
1065
1066 for( const VECTOR2I& pt : crossings )
1067 {
1068 path.insert( path.end(), { pt - along, pt - along + across, pt + along + across, pt + along } );
1069
1070 wxString msg = _( "A wire of net %s passes over a connection of another net at " //format:allow
1071 "(%.4f, %.4f) mm; it detours by %d nm to stay unconnected" ); //format:allow
1072
1073 m_reporter->Report(
1074 wxString::Format( msg, net->Name, pt.x / 10000.0, pt.y / 10000.0, DETOUR * 100 ),
1076 }
1077
1078 path.push_back( end );
1079
1080 for( size_t k = 0; k + 1 < path.size(); ++k )
1081 {
1082 SCH_LINE* wire = new SCH_LINE( path[k], LAYER_WIRE );
1083 wire->SetEndPoint( path[k + 1] );
1084
1085 if( style )
1086 wire->SetLineWidth( style->Width );
1087
1088 m_screen->Append( wire );
1089 }
1090 }
1091 }
1092
1093 // A junction with a pad style is a drawn junction dot
1094 for( SOURCE_NODE* node : TypedItems<SOURCE_NODE>( net->Nodes ) )
1095 {
1096 const SOURCE_JUNCTION* junction = dynamic_cast<const SOURCE_JUNCTION*>( node->Item );
1097 const SOURCE_PAD_STYLE* style =
1098 junction ? dynamic_cast<const SOURCE_PAD_STYLE*>( junction->Style ) : nullptr;
1099
1100 if( junction && junction->Style )
1101 m_screen->Append( new SCH_JUNCTION( toSheet( junction->Position ), style ? style->Size : 0 ) );
1102 }
1103 }
1104}
1105
1106
1107SCH_LABEL_BASE* SCH_BUILDER::addLabel( const wxString& aName, const VECTOR2I& aAt )
1108{
1109 // A name shared across a project's sheets needs a global label, and so does a
1110 // net a global power symbol names, since a local label of that name would be another net
1111 SCH_LABEL_BASE* label = nullptr;
1112
1113 if( m_names.Shared( aName ) || m_powerNets.count( aName.Upper() ) )
1114 label = new SCH_GLOBALLABEL( aAt, ToKiCadMarkup( aName ) );
1115 else
1116 label = new SCH_LABEL( aAt, ToKiCadMarkup( aName ) );
1117
1118 if( const SOURCE_TEXT_STYLE* style = defaultTextStyle( *m_design ) )
1119 label->SetTextSize( TextSize( *style ) );
1120
1121 m_labelledNets.insert( aName.Upper() );
1122 return label;
1123}
1124
1125
1127static SPIN_STYLE labelSpin( const SOURCE_NET_NAME& aName, const SOURCE_NODE& aNode, const wxString& aText )
1128{
1129 const SOURCE_TEXT_STYLE* style = dynamic_cast<const SOURCE_TEXT_STYLE*>( aName.TextStyle );
1130 int32_t rot = NormalizeAngle( aName.Rotation );
1131 bool vertical = ( rot >= 45000 && rot < 135000 ) || ( rot >= 225000 && rot < 315000 );
1132 int reading = rot >= 135000 && rot < 315000 ? -1 : 1;
1133
1134 // Stroke glyphs average about 0.6 of the text height in width; only the side of the node is decided by it
1135 double halfWidth = style ? style->Height * 0.6 * aText.length() / 2.0 : 0.0;
1136
1137 if( aName.Alignment == TEXT_ALIGN_RIGHT )
1138 reading = -reading;
1139 else if( aName.Alignment == TEXT_ALIGN_CENTRE )
1140 halfWidth = 0.0;
1141
1142 if( vertical )
1143 return aName.Position.Y + reading * halfWidth - aNode.Position.Y >= 0 ? SPIN_STYLE::UP : SPIN_STYLE::BOTTOM;
1144
1145 return aName.Position.X + reading * halfWidth - aNode.Position.X >= 0 ? SPIN_STYLE::RIGHT : SPIN_STYLE::LEFT;
1146}
1147
1148
1150{
1151 auto place = [&]( const wxString& aName, const SOURCE_NODE& aNode, const SOURCE_NET_NAME* aStyle )
1152 {
1153 SCH_LABEL_BASE* label = addLabel( aName, toSheet( aNode.Position ) );
1154 const SOURCE_TEXT_STYLE* style = dynamic_cast<const SOURCE_TEXT_STYLE*>( aStyle ? aStyle->TextStyle : nullptr );
1155
1156 if( aStyle )
1157 label->SetSpinStyle( labelSpin( *aStyle, aNode, aName ) );
1158
1159 if( style )
1160 label->SetTextSize( TextSize( *style ) );
1161
1162 m_screen->Append( label );
1163 };
1164
1165 for( SOURCE_NET* net : TypedItems<SOURCE_NET>( aDesign.Nets ) )
1166 {
1167 wxString name = m_names.Name( net->Name );
1168 std::vector<SOURCE_NODE*> nodes = TypedItems<SOURCE_NODE>( net->Nodes );
1169 std::map<const SOURCE_NODE*, const SOURCE_NODE*> root;
1170
1171 // A stored net is one object however it is drawn; KiCad needs every drawn piece named
1172 auto find = [&]( const SOURCE_NODE* aNode )
1173 {
1174 const SOURCE_NODE* r = aNode;
1175
1176 while( root[r] != r )
1177 r = root[r];
1178
1179 for( const SOURCE_NODE* n = aNode; n != r; )
1180 n = std::exchange( root[n], r );
1181
1182 return r;
1183 };
1184
1185 for( SOURCE_NODE* node : nodes )
1186 root[node] = node;
1187
1188 for( SOURCE_CONNECTION* conn : TypedItems<SOURCE_CONNECTION>( net->Connections ) )
1189 {
1190 const SOURCE_NODE* a = dynamic_cast<const SOURCE_NODE*>( conn->Node1 );
1191 const SOURCE_NODE* b = dynamic_cast<const SOURCE_NODE*>( conn->Node2 );
1192
1193 if( a && b && conn->Track && root.count( a ) && root.count( b ) )
1194 root[find( a )] = find( b );
1195 }
1196
1197 std::set<const SOURCE_NODE*> named;
1198 std::map<const SOURCE_NODE*, const SOURCE_NODE*> hiddenLabelOf;
1199 std::vector<const SOURCE_NODE*> pieces;
1200
1201 for( SOURCE_NODE* node : nodes )
1202 {
1203 const SOURCE_NODE* piece = find( node );
1204 const SOURCE_NET_NAME* label = dynamic_cast<const SOURCE_NET_NAME*>( node->NetName );
1205 bool free = !m_sharedPoints.count( toSheet( node->Position ) );
1206
1207 if( std::find( pieces.begin(), pieces.end(), piece ) == pieces.end() )
1208 pieces.push_back( piece );
1209
1210 if( m_powerNodes.count( node ) )
1211 named.insert( piece );
1212
1213 // A label on a point another net shares would join the two nets in KiCad
1214 if( label && label->Displayed && free )
1215 {
1216 place( name, *node, label );
1217 named.insert( piece );
1218 }
1219 else if( label && free && !hiddenLabelOf.count( piece ) )
1220 {
1221 hiddenLabelOf[piece] = node;
1222 }
1223 }
1224
1225 // A single automatic piece is named by KiCad itself; anything else must carry the stored name
1226 if( pieces.size() < 2 && !IsNamedNet( name ) )
1227 continue;
1228
1229 // The source draws no name here, so keep the label off pins: a junction, then a free wire end
1230 auto rank = []( const SOURCE_NODE* aNode )
1231 {
1232 return dynamic_cast<const SOURCE_JUNCTION*>( aNode->Item ) ? 1
1233 : dynamic_cast<const SOURCE_PAD_INSTANCE*>( aNode->Item ) ? 3
1234 : 2;
1235 };
1236
1237 for( const SOURCE_NODE* piece : pieces )
1238 {
1239 auto hidden = hiddenLabelOf.find( piece );
1240 const SOURCE_NODE* at = hidden != hiddenLabelOf.end() ? hidden->second : nullptr;
1241
1242 if( named.count( piece ) )
1243 continue;
1244
1245 for( SOURCE_NODE* node : nodes )
1246 {
1247 if( find( node ) == piece && !m_sharedPoints.count( toSheet( node->Position ) )
1248 && ( !at || rank( node ) < rank( at ) ) )
1249 {
1250 at = node;
1251 }
1252 }
1253
1254 if( at )
1255 place( name, *at, dynamic_cast<const SOURCE_NET_NAME*>( at->NetName ) );
1256 }
1257 }
1258}
1259
1260
1262{
1264 {
1265 const SOURCE_COMPONENT* part = dynamic_cast<const SOURCE_COMPONENT*>( comp->Component );
1266
1267 if( !part || !part->Board )
1268 continue;
1269
1270 // KiCad draws a pin common to several units once per unit and never joins the copies; the file has one
1271 // pin, on the net of whichever gate wires it
1272 std::map<wxString, const SOURCE_NET*> netOfPin;
1273
1274 for( SOURCE_SYMBOL_INSTANCE* inst : TypedItems<SOURCE_SYMBOL_INSTANCE>( comp->SymbolInstances ) )
1275 {
1276 for( SOURCE_PAD_INSTANCE* pad : TypedItems<SOURCE_PAD_INSTANCE>( isDrawn( *inst ) ? inst->Pads : nullptr ) )
1277 {
1278 const SOURCE_FREE_PAD* freePad = dynamic_cast<const SOURCE_FREE_PAD*>( pad->Pad );
1279 const SOURCE_NET* net = netOf( pad->Node );
1280
1281 if( freePad && net )
1282 {
1283 if( GATE_TERMINAL pin = ResolveTerminal( part->Board, inst->Gate, freePad->Number - 1 );
1284 pin.Mapped )
1285 netOfPin.emplace( pin.Number, net );
1286 }
1287 }
1288 }
1289
1290 for( SOURCE_SYMBOL_INSTANCE* inst : TypedItems<SOURCE_SYMBOL_INSTANCE>( comp->SymbolInstances ) )
1291 {
1292 const SOURCE_SYMBOL* sym = dynamic_cast<const SOURCE_SYMBOL*>( inst->Symbol );
1293
1294 for( SOURCE_PAD_INSTANCE* pad :
1295 TypedItems<SOURCE_PAD_INSTANCE>( sym && isDrawn( *inst ) ? inst->Pads : nullptr ) )
1296 {
1297 const SOURCE_FREE_PAD* freePad = dynamic_cast<const SOURCE_FREE_PAD*>( pad->Pad );
1298
1299 if( !freePad || pad->Node )
1300 continue;
1301
1302 GATE_TERMINAL pin = ResolveTerminal( part->Board, inst->Gate, freePad->Number - 1 );
1303 auto it = pin.Mapped ? netOfPin.find( pin.Number ) : netOfPin.end();
1304
1305 if( it == netOfPin.end() )
1306 continue;
1307
1308 // A copy on another net's point stays unconnected
1309 if( VECTOR2I at = toSheet( placePoint( *inst, *sym, freePad->Position ) ); !m_sharedPoints.count( at ) )
1310 m_screen->Append( addLabel( m_names.Name( it->second->Name ), at ) );
1311 }
1312 }
1313 }
1314}
1315
1316
1318{
1319 for( SOURCE_BUS* bus : TypedItems<SOURCE_BUS>( aDesign.Buses ) )
1320 {
1321 const SOURCE_SHAPE* shape = dynamic_cast<const SOURCE_SHAPE*>( bus->Shape );
1322 const SOURCE_LINE_STYLE* style = dynamic_cast<const SOURCE_LINE_STYLE*>( bus->Style );
1323 std::vector<const SOURCE_SEGMENT*> verts =
1324 shape ? ShapeVertices( *shape ) : std::vector<const SOURCE_SEGMENT*>();
1325
1326 for( size_t i = 0; i + 1 < verts.size(); ++i )
1327 {
1328 SCH_LINE* line = new SCH_LINE( toSheet( verts[i]->X, verts[i]->Y ), LAYER_BUS );
1329 line->SetEndPoint( toSheet( verts[i + 1]->X, verts[i + 1]->Y ) );
1330
1331 if( style )
1332 line->SetLineWidth( style->Width );
1333
1334 m_screen->Append( line );
1335 }
1336
1337 for( SOURCE_BUS_TERMINAL* term : TypedItems<SOURCE_BUS_TERMINAL>( bus->Terminals ) )
1338 {
1339 SCH_BUS_WIRE_ENTRY* entry = new SCH_BUS_WIRE_ENTRY( toSheet( term->BusEndPosition ) );
1340 entry->SetSize( toSheet( term->Position ) - toSheet( term->BusEndPosition ) );
1341 m_screen->Append( entry );
1342 }
1343
1344 if( shape )
1345 addBusAlias( *bus, *shape );
1346 }
1347}
1348
1349
1350void SCH_BUILDER::addBusAlias( const SOURCE_BUS& aBus, const SOURCE_SHAPE& aShape )
1351{
1352 // KiCad knows a bus's members only through its label, an alias of the nets a label or power symbol names
1353 std::vector<wxString> members;
1354
1355 for( OBJECT* obj : aBus.Nets )
1356 {
1357 const SOURCE_NET* net = dynamic_cast<const SOURCE_NET*>( obj );
1358 wxString name = net ? m_names.Name( net->Name ) : wxString();
1359
1360 if( net && ( m_labelledNets.count( name.Upper() ) || m_powerNets.count( name.Upper() ) ) )
1361 members.push_back( ToKiCadMarkup( name ) );
1362 }
1363
1364 std::vector<const SOURCE_SEGMENT*> verts = ShapeVertices( aShape );
1365
1366 if( members.empty() || verts.empty() )
1367 return;
1368
1369 wxString base;
1370
1371 for( wxUniChar ch : aBus.Name )
1372 base += wxIsalnum( ch ) ? ch : wxUniChar( '_' );
1373
1374 if( base.IsEmpty() )
1375 base = wxS( "BUS" );
1376
1377 wxString aliasName = base;
1378
1379 for( int i = 2; m_schematic->GetBusAlias( aliasName ); ++i )
1380 aliasName = wxString::Format( wxS( "%s_%d" ), base, i );
1381
1382 std::shared_ptr<BUS_ALIAS> alias = std::make_shared<BUS_ALIAS>();
1383 alias->SetName( aliasName );
1384 alias->SetMembers( members );
1385 m_screen->AddBusAlias( alias );
1386
1387 SCH_LABEL* label = new SCH_LABEL( toSheet( verts[0]->X, verts[0]->Y ), wxS( "{" ) + aliasName + wxS( "}" ) );
1388
1389 if( const SOURCE_TEXT_STYLE* style = defaultTextStyle( *m_design ) )
1390 label->SetTextSize( TextSize( *style ) );
1391
1392 m_screen->Append( label );
1393}
1394
1395} // namespace EASYPC
int index
const char * name
BOX2< VECTOR2L > BOX2L
Definition box2.h:916
BOX2< VECTOR2I > BOX2I
Definition box2.h:914
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
constexpr coord_type GetLeft() const
Definition box2.h:225
constexpr coord_type GetRight() const
Definition box2.h:214
constexpr coord_type GetTop() const
Definition box2.h:226
constexpr coord_type GetBottom() const
Definition box2.h:219
void buildBuses(const SOURCE_DESIGN &aDesign)
void placePinItems(const SOURCE_COMPONENT &aPart, const SOURCE_SYMBOL_INSTANCE &aInst, const SCH_FRAME &aFrame)
std::map< wxString, const SOURCE_SYMBOL * > m_projectSymbols
by name, first sheet wins
void placeFields(SCH_SYMBOL &aSymbol, const SOURCE_COMPONENT_INSTANCE &aComp, const SOURCE_SYMBOL_INSTANCE &aInst, bool aPower, const SCH_FRAME &aFrame)
void addBusAlias(const SOURCE_BUS &aBus, const SOURCE_SHAPE &aShape)
std::set< const SOURCE_NODE * > m_powerNodes
const SOURCE_DESIGN * m_design
void buildWires(const SOURCE_DESIGN &aDesign)
std::set< wxString > m_labelledNets
upper-cased nets a label names
SCH_BUILDER(SCHEMATIC *aSchematic, const SCH_NET_NAMES &aNames, REPORTER *aReporter)
void buildSymbols(const SOURCE_DESIGN &aDesign, const SCH_SHEET_PATH &aSheetPath)
void BuildSheet(const DESIGN_DOCUMENT &aDoc, SCH_SHEET *aSheet, const SCH_SHEET_PATH &aSheetPath)
SCH_LABEL_BASE * addLabel(const wxString &aName, const VECTOR2I &aAt)
A local label, global when the name crosses sheets or a global power symbol names it.
VECTOR2I toSheet(int32_t aX, int32_t aY) const
void SetProjectSymbols(const std::vector< const DESIGN_DOCUMENT * > &aDocs)
Symbols of every sheet, for gates placed on a sheet other than the one being built.
std::set< VECTOR2I > m_sharedPoints
points where connections of different nets meet
void buildLabels(const SOURCE_DESIGN &aDesign)
void computeOffset(const SOURCE_DESIGN &aDesign)
int32_t m_originX
design point at the sheet's top left corner
void buildCommonPinCopies(const SOURCE_DESIGN &aDesign)
std::set< wxString > m_powerNets
upper-cased nets a power symbol names
const SCH_NET_NAMES & m_names
Project-wide net naming: a user name takes the spelling of its first occurrence.
void AddSheet(const DESIGN_DOCUMENT &aDoc)
bool Shared(const wxString &aName) const
A user name used on more than one sheet, which is one net across the project.
wxString Name(const wxString &aStoredName) const
std::map< wxString, int > m_sheetCount
std::map< wxString, wxString > m_canonical
upper-cased name to first spelling
bool CanMeasure() const
False for a TrueType style; the measuring calls throw IO_ERROR for one.
BOX2I TextBox(const wxString &aText, const VECTOR2I &aAnchor, int32_t aAngle, bool aMirrored, int aHAlign, int aVAlign=TEXT_V_BASELINE) const
Every line's cell, inflated by half the pen width, mirrored about the anchor and bounded after rotati...
bool IsHorizontal() const
Definition eda_angle.h:141
virtual VECTOR2I GetTextPos() const
Definition eda_text.h:313
virtual void SetTextSize(VECTOR2I aNewSize, bool aEnforceMinTextSize=true)
Definition eda_text.cpp:512
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:239
virtual void SetVisible(bool aVisible)
Definition eda_text.cpp:347
virtual EDA_ANGLE GetTextAngle() const
Definition eda_text.h:178
GR_TEXT_V_ALIGN_T GetVertJustify() const
Definition eda_text.h:242
virtual void SetTextAngle(const EDA_ANGLE &aAngle)
Definition eda_text.cpp:268
A logical library item identifier and consists of various portions much like a URI.
Definition lib_id.h:45
Define a library symbol object.
Definition lib_symbol.h:114
A pure virtual class used to derive REPORTER objects from.
Definition reporter.h:73
void SetSize(const VECTOR2I &aSize)
Class for a wire to bus entry.
void SetEffectiveHorizJustify(GR_TEXT_H_ALIGN_T)
void SetEffectiveVertJustify(GR_TEXT_V_ALIGN_T)
void SetPosition(const VECTOR2I &aPosition) override
void SetText(const wxString &aText) override
virtual void SetSpinStyle(SPIN_STYLE aSpinStyle)
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:39
void SetLineWidth(const int aSize)
Definition sch_line.cpp:437
void SetEndPoint(const VECTOR2I &aPosition)
Definition sch_line.h:146
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
SCH_SCREEN * GetScreen() const
Definition sch_sheet.h:145
void SetRef(const SCH_SHEET_PATH *aSheet, const wxString &aReference)
Set the reference for the given sheet path for this symbol.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const override
Populate a std::vector with SCH_FIELDs, sorted in ordinal order.
void SetValueFieldText(const wxString &aValue, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString)
SCH_FIELD * AddField(const SCH_FIELD &aField)
Add a field to the symbol.
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 B
Definition seg.h:46
Spin style for labels of all kinds on schematics.
Definition sch_label.h:38
void SetTransform(const TRANSFORM &aTransform)
Definition symbol.h:249
const TRANSFORM & GetTransform() const
Definition symbol.h:247
Hold the information shown in the lower right corner of a plot, printout, or editing view.
Definition title_block.h:38
for transforming drawing coordinates for a wxDC device context.
Definition transform.h:42
VECTOR2< T > Resize(T aNewLength) const
Return a vector of the same direction, but length specified in aNewLength.
Definition vector2d.h:406
Placed instances and connectivity: component, symbol and pad instances, nets, nodes,...
Shapes, vertices and the free-standing drawn items.
Free pads, apart because they derive from a connectivity class.
Symbols, components and gates, embedded in designs or the single object of a library item stream.
The design document and the design parameter tables the importers use.
Design items, attributes, styles, layers, net classes and spacings.
Title block and page size, shared by the board and schematic builders.
Loading designs, library items and projects.
Builds KiCad sheets from Easy-PC / DesignSpark schematic designs.
Schematic graphics, texts and symbols shared by the sheet builder and the symbol libraries,...
Easy-PC's text measurement, so text lands where Easy-PC draws it.
Design units of 100 nm and angles of thousandths of a degree, anticlockwise from +X with Y up.
#define _(s)
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:445
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:444
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
std::string source
@ LAYER_WIRE
Definition layer_ids.h:474
@ LAYER_NOTES
Definition layer_ids.h:489
@ LAYER_BUS
Definition layer_ids.h:475
bool TextStaysUpright(const SOURCE_DESIGN &aDesign, bool aSchematic)
Whether aDesign's text is drawn upright: the design's flag, which old schematics imply,...
static int32_t floorTo(int64_t aValue, int32_t aGrid)
GATE_TERMINAL ResolveTerminal(const SOURCE_PCB_COMPONENT *aPcb, int aGate, int aTerminal)
Terminal aTerminal (0-based) of gate aGate; formats before 9000 map a bare pad number,...
bool IsNamedNet(const wxString &aName)
True unless aName is an automatic net name (N or n and digits, an optional !sheet!...
std::unique_ptr< SCH_TEXT > ConvertFreeText(const SOURCE_FREE_TEXT &aText, const SCH_FRAME &aFrame, SCH_LAYER_ID aLayer, int aUnit, bool aKeepUpright)
int32_t UprightRotation(int32_t aAngle, bool aKeepUpright)
With text kept upright, an angle above 135 and up to 305 degrees turns by 180.
static POINT32 placePoint(const SOURCE_SYMBOL_INSTANCE &aInst, const SOURCE_SYMBOL &aSym, const POINT32 &aLocal)
Symbol point to design point: subtract the symbol origin, mirror in X, rotate anticlockwise,...
static wxString attributeValue(const SOURCE_COMPONENT_INSTANCE &aComp, const SOURCE_COMPONENT &aPart, const wxString &aName)
The value of the part's first attribute named aName, or empty.
PAGE_INFO PageForExtents(const BOX2L &aExtentsNm)
Easy-PC stores no page size, so the first of A4 to A0 then A to E, landscape before portrait,...
std::unique_ptr< LIB_SYMBOL > ConvertComponentSymbol(const SCH_COMPONENT_SOURCE &aSrc, const LIB_ID &aId)
One unit per gate in symbol-local coordinates, zero-length passive pins at the pads,...
static bool isDrawn(const SOURCE_SYMBOL_INSTANCE &aInst)
Gates the import draws: placed ones, and unplaced ones whose pins are still on nets.
bool DrawsUpright(const SOURCE_TEXT_POSITION &aPos, bool aKeepUpright)
True when a design that keeps text upright turns aPos about the far end of its first line.
void PointRotate(double aPx, double aPy, int32_t aAngle, double aCx, double aCy, int32_t &aOutX, int32_t &aOutY)
Rotate aPx, aPy anticlockwise by aAngle about aCx, aCy as Easy-PC places points: in double with exact...
constexpr double PAGE_MARGIN_MM
Margin added on every side of the drawn extents before choosing a page, in millimetres.
static SOURCE_TEXT_POSITION placedText(const SOURCE_SYMBOL_INSTANCE &aInst, const SOURCE_SYMBOL &aSym, const SOURCE_TEXT_POSITION &aLocal)
A symbol-local text position placed on the sheet with the instance transform.
static constexpr int32_t SHEET_ORIGIN_GRID
The sheet origin snaps to 0.1 inch, keeping items on Easy-PC grids on KiCad's 50 mil grid.
std::vector< std::unique_ptr< SCH_SHAPE > > ConvertShapeItem(const SOURCE_SHAPE_ITEM &aItem, const SCH_FRAME &aFrame, SCH_LAYER_ID aLayer, int aUnit)
A shape item with its own line style and fill.
static const SOURCE_NET * netOf(const OBJECT *aNode)
static constexpr int32_t DETOUR
Offset that keeps a wire off another net's connection point, far below drawing resolution.
static std::vector< VALUE_LINE > valueLines(const SOURCE_VALUE_POSITION &aVp, const SOURCE_COMPONENT_INSTANCE &aComp, const SOURCE_COMPONENT &aPart, const SOURCE_SYMBOL_INSTANCE &aInst)
@ SCH_SYMBOL
one item stream of a Schematic Symbol Library
std::vector< T * > TypedItems(const OBJECT *aList)
The items of ListItems that are a T, in order.
static bool collinearOverlap(const SEG &aA, const SEG &aB)
Two segments on one line sharing more than a point.
static constexpr int32_t PAGE_MARGIN
static bool isScmOnly(const SOURCE_COMPONENT &aPart)
Schematic-only part: no package, an empty package name, or no gate pin mapped to a pad.
constexpr int32_t NormalizeAngle(int32_t aAngle)
Wrap an angle into [0, ANGLE_FULL_TURN)
wxString ToKiCadMarkup(const wxString &aText)
A displayed string in KiCad's markup.
static SPIN_STYLE labelSpin(const SOURCE_NET_NAME &aName, const SOURCE_NODE &aNode, const wxString &aText)
Label orientation from the stored text rotation and alignment, judged by the middle of the text.
VECTOR2I TextSize(const SOURCE_TEXT_STYLE &aStyle)
KiCad text size for a source text style: its height as the width, its capital height as the height.
@ VALUE_ATTRIBUTE
the attribute the value position names
void ApplyTextPosition(EDA_TEXT &aText, const SOURCE_TEXT_POSITION &aPos, const SCH_FRAME &aFrame, bool aKeepUpright, const wxString &aMeasured)
Place any KiCad text as the source position says: anchor, angle, mirror, justification and style.
static const SOURCE_TEXT_STYLE * defaultTextStyle(const SOURCE_DESIGN &aDesign)
static wxString joinLines(const std::vector< VALUE_LINE > &aLines)
static TRANSFORM placementTransform(int32_t aAngle, bool aMirrored)
KiCad transform for a stored placement: mirror in X, then rotate anticlockwise (Y up)
std::vector< const SOURCE_SEGMENT * > ShapeVertices(const SOURCE_SHAPE &aShape)
A shape's vertices in drawing order, following next references for formats 1 and 2.
static std::vector< const SOURCE_ATTRIBUTE * > partAttributes(const SOURCE_COMPONENT_INSTANCE &aComp, const SOURCE_COMPONENT &aPart)
Package attributes then the instance's own, an instance attribute overriding the package's of the sam...
void FillTitleBlock(const DESIGN_DOCUMENT &aDoc, TITLE_BLOCK &aTitleBlock)
Fill a title block from the design's SummaryInformation property set: title from Title,...
@ PT_POWER_IN
power input (GND, VCC for ICs). Must be connected to a power output.
Definition pin_type.h:42
@ RPT_SEVERITY_WARNING
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.
wxString EscapeString(const wxString &aSource, ESCAPE_CONTEXT aContext)
The Escape/Unescape routines use HTML-entity-reference-style encoding to handle characters which are:...
@ CTX_LIBID
std::unique_ptr< OBJECT > Design
design root, not in the load array
std::vector< std::unique_ptr< OBJECT > > Objects
What a package's gate map says about one gate terminal.
wxString Display
the number shown beside the pin, the part before '=' when there is one
Root of every deserialized object.
A point read as two int32 values.
Everything one component LIB_SYMBOL is made from.
Design to KiCad mapping: X shifted, Y negated about the origin.
VECTOR2I Map(int64_t aX, int64_t aY) const
std::vector< OBJECT * > Nets
SOURCE_SCM_COMPONENT * Schematic
OBJECT * Attributes
attribute array
OBJECT * Parent
null is the document in a design, nothing in a library item
The document: OLE items, then the design.
Every drawn shape, pour and dimension part.
A pad of a symbol definition.
One gate's terminals to footprint pads.
A schematic symbol and its pin names.
std::vector< wxString > PinNames
terminal t is the symbol pad numbered t + 1
A schematic net label owned by a node.
OBJECT * GateMaps
one per schematic gate in order
Placed pin names and numbers.
OBJECT * Definition
the pin name or number instantiated
A placed footprint (gate -1) or a placed schematic gate.
OBJECT * ValuePositions
below 10003 built from the stored symbol name
Footprints and schematic symbols alike.
OBJECT * Shapes
free copper list
OBJECT * Texts
free text list
OBJECT * Pads
free pad list
int32_t Height
the accessor is GetWidth but it is the text height
OBJECT * Style
track style of the span leaving this vertex
One line of the text a value position shows.
FIELD_T
The set of all field indices assuming an array like sequence that a SCH_COMPONENT or LIB_PART can hol...
@ USER
The field ID hasn't been set yet; field is invalid.
@ REFERENCE
Field Reference of part, i.e. "IC21".
@ VALUE
Field Value of part, i.e. "3.3K".
std::string path
KIBIS_COMPONENT * comp
KIBIS_PIN * pin
static std::vector< int > candidates(const SEGMENT_INDEX &aIndex, const SEG &aQuery, int aPadding)
VECTOR2I end
GR_TEXT_H_ALIGN_T
This is API surface mapped to common.types.HorizontalAlignment.
GR_TEXT_V_ALIGN_T
This is API surface mapped to common.types.VertialAlignment.
#define M_PI
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707
VECTOR2< int64_t > VECTOR2L
Definition vector2d.h:709