KiCad PCB EDA Suite
Loading...
Searching...
No Matches
autoplace_fields.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2015 Chris Pavlina <[email protected]>
5 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25/******************************************************************************
26 * Field autoplacer: Tries to find an optimal place for symbol fields, and places them there.
27 * There are two modes: "auto"-autoplace, and "manual" autoplace.
28 * Auto mode is for when the process is run automatically, like when rotating parts, and it
29 * avoids doing things that would be helpful for the final positioning but annoying if they
30 * happened without permission.
31 * Short description of the process:
32 *
33 * 1. Compute the dimensions of the fields' bounding box ::computeFBoxSize
34 * 2. Determine which side the fields will go on. ::chooseSideForFields
35 * 1. Sort the four sides in preference order,
36 * depending on the symbol's shape and
37 * orientation ::getPreferredSides
38 * 2. If in manual mode, sift out the sides that would
39 * cause fields to overlap other items ::getCollidingSides
40 * 3. If any remaining sides have zero pins there,
41 * choose the highest zero-pin side according to
42 * preference order.
43 * 4. If all sides have pins, choose the side with the
44 * fewest pins.
45 * 3. Compute the position of the fields' bounding box ::fieldBoxPlacement
46 * 4. In manual mode, shift the box vertically if possible
47 * to fit fields between adjacent wires ::fitFieldsBetweenWires
48 * 5. Move all fields to their final positions
49 * 1. Re-justify fields if options allow that ::justifyField
50 * 2. Round to a 50-mil grid coordinate if desired
51 */
52
53#include <boost/range/adaptor/reversed.hpp>
54
55#include <sch_edit_frame.h>
56#include <sch_line.h>
57#include <kiface_base.h>
58#include <algorithm>
59#include <tool/tool_manager.h>
60#include <core/arraydim.h>
61
62#define FIELD_PADDING schIUScale.MilsToIU( 15 ) // arbitrarily chosen for aesthetics
63#define WIRE_V_SPACING schIUScale.MilsToIU( 100 )
64#define HPADDING schIUScale.MilsToIU( 25 ) // arbitrarily chosen for aesthetics
65#define VPADDING schIUScale.MilsToIU( 15 ) // arbitrarily chosen for aesthetics
66
70template<typename T> T round_n( const T& value, const T& n, bool aRoundUp )
71{
72 if( value % n )
73 return n * (value / n + (aRoundUp ? 1 : 0));
74 else
75 return value;
76}
77
78
80{
81public:
82 typedef VECTOR2I SIDE;
85
87 {
89 unsigned pins;
90 };
91
97
98 AUTOPLACER( SYMBOL* aSymbol, SCH_SCREEN* aScreen ) :
99 m_screen( aScreen ),
100 m_symbol( aSymbol ),
101 m_is_power_symbol( false )
102 {
103 m_symbol->GetFields( m_fields, /* aVisibleOnly */ true );
104
105 auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
106 wxASSERT( cfg );
107
108 m_allow_rejustify = false;
109 m_align_to_grid = true;
110
111 if( cfg )
112 {
113 m_allow_rejustify = cfg->m_AutoplaceFields.allow_rejustify;
114 m_align_to_grid = cfg->m_AutoplaceFields.align_to_grid;
115 }
116
117 m_symbol_bbox = m_symbol->GetBodyBoundingBox();
118 m_fbox_size = computeFBoxSize( /* aDynamic */ true );
119
120 if( SCH_SYMBOL* schSymbol = dynamic_cast<SCH_SYMBOL*>( m_symbol ) )
121 m_is_power_symbol = !schSymbol->IsInNetlist();
122
123 if( aScreen )
125 }
126
133 {
134 bool forceWireSpacing = false;
135 SIDE_AND_NPINS sideandpins = chooseSideForFields( aAlgo == AUTOPLACE_MANUAL );
136 SIDE field_side = sideandpins.side;
137 VECTOR2I fbox_pos = fieldBoxPlacement( sideandpins );
138 BOX2I field_box( fbox_pos, m_fbox_size );
139
140 if( aAlgo == AUTOPLACE_MANUAL )
141 forceWireSpacing = fitFieldsBetweenWires( &field_box, field_side );
142
143 // Move the fields
144 int last_y_coord = field_box.GetTop();
145
146 for( SCH_FIELD* field : m_fields )
147 {
148 if( !field->IsVisible() || !field->CanAutoplace() )
149 continue;
150
152 {
153 if( sideandpins.pins > 0 )
154 {
155 if( field_side == SIDE_TOP || field_side == SIDE_BOTTOM )
156 justifyField( field, SIDE_RIGHT );
157 else
158 justifyField( field, SIDE_TOP );
159 }
160 else
161 {
162 justifyField( field, field_side );
163 }
164 }
165
166 VECTOR2I pos( fieldHPlacement( field, field_box ),
167 fieldVPlacement( field, field_box, &last_y_coord, !forceWireSpacing ) );
168
169 if( m_align_to_grid )
170 {
171 if( abs( field_side.x ) > 0 )
172 pos.x = round_n( pos.x, schIUScale.MilsToIU( 50 ), field_side.x >= 0 );
173
174 if( abs( field_side.y ) > 0 )
175 pos.y = round_n( pos.y, schIUScale.MilsToIU( 50 ), field_side.y >= 0 );
176 }
177
178 field->SetPosition( pos );
179 }
180 }
181
182protected:
187 VECTOR2I computeFBoxSize( bool aDynamic )
188 {
189 int max_field_width = 0;
190 int total_height = 0;
191
192 for( SCH_FIELD* field : m_fields )
193 {
194 if( !field->IsVisible() || !field->CanAutoplace() )
195 {
196 continue;
197 }
198
199 if( m_symbol->GetTransform().y1 )
200 field->SetTextAngle( ANGLE_VERTICAL );
201 else
202 field->SetTextAngle( ANGLE_HORIZONTAL );
203
204 BOX2I bbox = field->GetBoundingBox();
205 int field_width = bbox.GetWidth();
206 int field_height = bbox.GetHeight();
207
208 max_field_width = std::max( max_field_width, field_width );
209
210 if( !aDynamic )
211 total_height += WIRE_V_SPACING;
212 else if( m_align_to_grid )
213 total_height += round_n( field_height, schIUScale.MilsToIU( 50 ), true );
214 else
215 total_height += field_height + FIELD_PADDING;
216 }
217
218 return VECTOR2I( max_field_width, total_height );
219 }
220
225 {
226 PIN_ORIENTATION pin_orient = aPin->PinDrawOrient( m_symbol->GetTransform() );
227
228 switch( pin_orient )
229 {
234 default:
235 wxFAIL_MSG( wxS( "Invalid pin orientation" ) );
236 return SIDE_LEFT;
237 }
238 }
239
243 unsigned pinsOnSide( SIDE aSide )
244 {
245 unsigned pin_count = 0;
246
247 for( SCH_PIN* each_pin : m_symbol->GetPins() )
248 {
249 if( !each_pin->IsVisible() && !m_is_power_symbol )
250 continue;
251
252 if( getPinSide( each_pin ) == aSide )
253 ++pin_count;
254 }
255
256 return pin_count;
257 }
258
263 void getPossibleCollisions( std::vector<SCH_ITEM*>& aItems )
264 {
265 wxCHECK_RET( m_screen, wxS( "getPossibleCollisions() with null m_screen" ) );
266
267 BOX2I symbolBox = m_symbol->GetBodyAndPinsBoundingBox();
268 std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
269
270 for( SIDE_AND_NPINS& side : sides )
271 {
272 BOX2I box( fieldBoxPlacement( side ), m_fbox_size );
273 box.Merge( symbolBox );
274
275 for( SCH_ITEM* item : m_screen->Items().Overlapping( box ) )
276 {
277 if( SCH_SYMBOL* candidate = dynamic_cast<SCH_SYMBOL*>( item ) )
278 {
279 if( candidate == m_symbol )
280 continue;
281
282 std::vector<SCH_FIELD*> fields;
283 candidate->GetFields( fields, /* aVisibleOnly */ true );
284
285 for( SCH_FIELD* field : fields )
286 aItems.push_back( field );
287 }
288
289 aItems.push_back( item );
290 }
291 }
292 }
293
298 std::vector<SCH_ITEM*> filterCollisions( const BOX2I& aRect )
299 {
300 std::vector<SCH_ITEM*> filtered;
301
302 for( SCH_ITEM* item : m_colliders )
303 {
304 BOX2I item_box;
305
306 if( SCH_SYMBOL* item_comp = dynamic_cast<SCH_SYMBOL*>( item ) )
307 item_box = item_comp->GetBodyAndPinsBoundingBox();
308 else
309 item_box = item->GetBoundingBox();
310
311 if( item_box.Intersects( aRect ) )
312 filtered.push_back( item );
313 }
314
315 return filtered;
316 }
317
322 std::vector<SIDE_AND_NPINS> getPreferredSides()
323 {
324 SIDE_AND_NPINS sides_init[] = {
329 };
330 std::vector<SIDE_AND_NPINS> sides( sides_init, sides_init + arrayDim( sides_init ) );
331
332 int orient = m_symbol->GetOrientation();
333 int orient_angle = orient & 0xff; // enum is a bitmask
334 bool h_mirrored = ( ( orient & SYM_MIRROR_X )
335 && ( orient_angle == SYM_ORIENT_0 || orient_angle == SYM_ORIENT_180 ) );
336 double w = double( m_symbol_bbox.GetWidth() );
337 double h = double( m_symbol_bbox.GetHeight() );
338
339 // The preferred-sides heuristics are a bit magical. These were determined mostly
340 // by trial and error.
341
343 {
344 // For power symbols, we generally want the label at the top first.
345 switch( orient_angle )
346 {
347 case SYM_ORIENT_0:
348 std::swap( sides[0], sides[1] );
349 std::swap( sides[1], sides[3] );
350 // TOP, BOTTOM, RIGHT, LEFT
351 break;
352 case SYM_ORIENT_90:
353 std::swap( sides[0], sides[2] );
354 std::swap( sides[1], sides[2] );
355 // LEFT, RIGHT, TOP, BOTTOM
356 break;
357 case SYM_ORIENT_180:
358 std::swap( sides[0], sides[3] );
359 // BOTTOM, TOP, LEFT, RIGHT
360 break;
361 case SYM_ORIENT_270:
362 std::swap( sides[1], sides[2] );
363 // RIGHT, LEFT, TOP, BOTTOM
364 break;
365 }
366 }
367 else
368 {
369 // If the symbol is horizontally mirrored, swap left and right
370 if( h_mirrored )
371 {
372 std::swap( sides[0], sides[2] );
373 }
374
375 // If the symbol is very long or is a power symbol, swap H and V
376 if( w/h > 3.0 )
377 {
378 std::swap( sides[0], sides[1] );
379 std::swap( sides[1], sides[3] );
380 }
381 }
382
383 return sides;
384 }
385
389 std::vector<SIDE_AND_COLL> getCollidingSides()
390 {
391 SIDE sides_init[] = { SIDE_RIGHT, SIDE_TOP, SIDE_LEFT, SIDE_BOTTOM };
392 std::vector<SIDE> sides( sides_init, sides_init + arrayDim( sides_init ) );
393 std::vector<SIDE_AND_COLL> colliding;
394
395 // Iterate over all sides and find the ones that collide
396 for( SIDE side : sides )
397 {
398 SIDE_AND_NPINS sideandpins;
399 sideandpins.side = side;
400 sideandpins.pins = pinsOnSide( side );
401
402 BOX2I box( fieldBoxPlacement( sideandpins ), m_fbox_size );
403
404 COLLISION collision = COLLIDE_NONE;
405
406 for( SCH_ITEM* collider : filterCollisions( box ) )
407 {
408 SCH_LINE* line = dynamic_cast<SCH_LINE*>( collider );
409
410 if( line && !side.x )
411 {
412 VECTOR2I start = line->GetStartPoint(), end = line->GetEndPoint();
413
414 if( start.y == end.y && collision != COLLIDE_OBJECTS )
415 collision = COLLIDE_H_WIRES;
416 else
417 collision = COLLIDE_OBJECTS;
418 }
419 else
420 {
421 collision = COLLIDE_OBJECTS;
422 }
423 }
424
425 if( collision != COLLIDE_NONE )
426 colliding.push_back( { side, collision } );
427 }
428
429 return colliding;
430 }
431
436 SIDE_AND_NPINS chooseSideFiltered( std::vector<SIDE_AND_NPINS>& aSides,
437 const std::vector<SIDE_AND_COLL>& aCollidingSides,
438 COLLISION aCollision,
439 SIDE_AND_NPINS aLastSelection)
440 {
441 SIDE_AND_NPINS sel = aLastSelection;
442
443 std::vector<SIDE_AND_NPINS>::iterator it = aSides.begin();
444
445 while( it != aSides.end() )
446 {
447 bool collide = false;
448
449 for( SIDE_AND_COLL collision : aCollidingSides )
450 {
451 if( collision.side == it->side && collision.collision == aCollision )
452 collide = true;
453 }
454
455 if( !collide )
456 {
457 ++it;
458 }
459 else
460 {
461 if( it->pins <= sel.pins )
462 {
463 sel.pins = it->pins;
464 sel.side = it->side;
465 }
466
467 it = aSides.erase( it );
468 }
469 }
470
471 return sel;
472 }
473
479 SIDE_AND_NPINS chooseSideForFields( bool aAvoidCollisions )
480 {
481 std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
482
483 std::reverse( sides.begin(), sides.end() );
484 SIDE_AND_NPINS side = { VECTOR2I( 1, 0 ), UINT_MAX };
485
486 if( aAvoidCollisions )
487 {
488 std::vector<SIDE_AND_COLL> colliding_sides = getCollidingSides();
489 side = chooseSideFiltered( sides, colliding_sides, COLLIDE_OBJECTS, side );
490 side = chooseSideFiltered( sides, colliding_sides, COLLIDE_H_WIRES, side );
491 }
492
493 for( SIDE_AND_NPINS& each_side : sides | boost::adaptors::reversed )
494 {
495 if( !each_side.pins ) return each_side;
496 }
497
498 for( SIDE_AND_NPINS& each_side : sides )
499 {
500 if( each_side.pins <= side.pins )
501 {
502 side.pins = each_side.pins;
503 side.side = each_side.side;
504 }
505 }
506
507 return side;
508 }
509
515 void justifyField( SCH_FIELD* aField, SIDE aFieldSide )
516 {
517 // Justification is set twice to allow IsHorizJustifyFlipped() to work correctly.
518 aField->SetHorizJustify( ToHAlignment( -aFieldSide.x ) );
519 if( aField->IsHorizJustifyFlipped() )
521
523 }
524
529 {
530 VECTOR2I fbox_center = m_symbol_bbox.Centre();
531 int offs_x = ( m_symbol_bbox.GetWidth() + m_fbox_size.x ) / 2;
532 int offs_y = ( m_symbol_bbox.GetHeight() + m_fbox_size.y ) / 2;
533
534 if( aFieldSideAndPins.side.x != 0 )
535 offs_x += HPADDING;
536 else if( aFieldSideAndPins.side.y != 0 )
537 offs_y += VPADDING;
538
539 fbox_center.x += aFieldSideAndPins.side.x * offs_x;
540 fbox_center.y += aFieldSideAndPins.side.y * offs_y;
541
542 int x = fbox_center.x - ( m_fbox_size.x / 2 );
543 int y = fbox_center.y - ( m_fbox_size.y / 2 );
544
545 auto getPinsBox =
546 [&]( const VECTOR2I& aSide )
547 {
548 BOX2I pinsBox;
549
550 for( SCH_PIN* each_pin : m_symbol->GetPins() )
551 {
552 if( !each_pin->IsVisible() && !m_is_power_symbol )
553 continue;
554
555 if( getPinSide( each_pin ) == aSide )
556 pinsBox.Merge( each_pin->GetBoundingBox() );
557 }
558
559 return pinsBox;
560 };
561
562 if( aFieldSideAndPins.pins > 0 )
563 {
564 BOX2I pinsBox = getPinsBox( aFieldSideAndPins.side );
565
566 if( aFieldSideAndPins.side == SIDE_TOP || aFieldSideAndPins.side == SIDE_BOTTOM )
567 {
568 x = pinsBox.GetRight() + ( HPADDING * 2 );
569 }
570 else if( aFieldSideAndPins.side == SIDE_RIGHT || aFieldSideAndPins.side == SIDE_LEFT )
571 {
572 y = pinsBox.GetTop() - ( m_fbox_size.y + ( VPADDING * 2 ) );
573 }
574 }
575
576 return VECTOR2I( x, y );
577 }
578
583 bool fitFieldsBetweenWires( BOX2I* aBox, SIDE aSide )
584 {
585 if( aSide != SIDE_TOP && aSide != SIDE_BOTTOM )
586 return false;
587
588 std::vector<SCH_ITEM*> colliders = filterCollisions( *aBox );
589
590 if( colliders.empty() )
591 return false;
592
593 // Find the offset of the wires for proper positioning
594 int offset = 0;
595
596 for( SCH_ITEM* item : colliders )
597 {
598 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
599
600 if( !line )
601 return false;
602
603 VECTOR2I start = line->GetStartPoint(), end = line->GetEndPoint();
604
605 if( start.y != end.y )
606 return false;
607
608 int this_offset = (3 * WIRE_V_SPACING / 2) - ( start.y % WIRE_V_SPACING );
609
610 if( offset == 0 )
611 offset = this_offset;
612 else if( offset != this_offset )
613 return false;
614 }
615
616 // At this point we are recomputing the field box size. Do not
617 // return false after this point.
618 m_fbox_size = computeFBoxSize( /* aDynamic */ false );
619
620 VECTOR2I pos = aBox->GetPosition();
621
622 pos.y = round_n( pos.y, WIRE_V_SPACING, aSide == SIDE_BOTTOM );
623
624 aBox->SetOrigin( pos );
625 return true;
626 }
627
636 int fieldHPlacement( SCH_FIELD* aField, const BOX2I& aFieldBox )
637 {
638 int field_hjust;
639 int field_xcoord;
640
641 if( aField->IsHorizJustifyFlipped() )
642 field_hjust = -aField->GetHorizJustify();
643 else
644 field_hjust = aField->GetHorizJustify();
645
646 switch( field_hjust )
647 {
649 field_xcoord = aFieldBox.GetLeft();
650 break;
652 field_xcoord = aFieldBox.Centre().x;
653 break;
655 field_xcoord = aFieldBox.GetRight();
656 break;
657 default:
658 wxFAIL_MSG( wxS( "Unexpected value for SCH_FIELD::GetHorizJustify()" ) );
659 field_xcoord = aFieldBox.Centre().x; // Most are centered
660 }
661
662 return field_xcoord;
663 }
664
676 int fieldVPlacement( SCH_FIELD* aField, const BOX2I& aFieldBox, int* aAccumulatedPosition,
677 bool aDynamic )
678 {
679 int field_height;
680 int padding;
681
682 if( !aDynamic )
683 {
684 field_height = WIRE_V_SPACING / 2;
685 padding = WIRE_V_SPACING / 2;
686 }
687 else if( m_align_to_grid )
688 {
689 field_height = aField->GetBoundingBox().GetHeight();
690 padding = round_n( field_height, schIUScale.MilsToIU( 50 ), true ) - field_height;
691 }
692 else
693 {
694 field_height = aField->GetBoundingBox().GetHeight();
695 padding = FIELD_PADDING;
696 }
697
698 int placement = *aAccumulatedPosition + padding / 2 + field_height / 2;
699
700 *aAccumulatedPosition += padding + field_height;
701
702 return placement;
703 }
704
705private:
708 std::vector<SCH_FIELD*> m_fields;
709 std::vector<SCH_ITEM*> m_colliders;
715};
716
717
722
723
725{
726 if( aAlgo == AUTOPLACE_MANUAL )
727 wxASSERT_MSG( aScreen, wxS( "A SCH_SCREEN ptr must be given for manual autoplacement" ) );
728
729 AUTOPLACER autoplacer( this, aScreen );
730 autoplacer.DoAutoplace( aAlgo );
731
732 switch( aAlgo )
733 {
736 default: wxFAIL_MSG( "Unknown autoplace algorithm" ); break;
737 }
738}
739
740
742{
743 if( aAlgo == AUTOPLACE_MANUAL )
744 wxFAIL_MSG( wxS( "Manual autoplacement not supported for LIB_SYMBOLs" ) );
745
746 AUTOPLACER autoplacer( this, aScreen );
747 autoplacer.DoAutoplace( aAlgo );
748
749 switch( aAlgo )
750 {
753 default: wxFAIL_MSG( "Unknown autoplace algorithm" ); break;
754 }
755}
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition arraydim.h:31
#define HPADDING
#define FIELD_PADDING
#define VPADDING
#define WIRE_V_SPACING
T round_n(const T &value, const T &n, bool aRoundUp)
Round up/down to the nearest multiple of n.
constexpr EDA_IU_SCALE schIUScale
Definition base_units.h:114
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
VECTOR2I computeFBoxSize(bool aDynamic)
Compute and return the size of the fields' bounding box.
VECTOR2I fieldBoxPlacement(SIDE_AND_NPINS aFieldSideAndPins)
Return the position of the field bounding box.
SIDE getPinSide(SCH_PIN *aPin)
Return the side that a pin is on.
int fieldVPlacement(SCH_FIELD *aField, const BOX2I &aFieldBox, int *aAccumulatedPosition, bool aDynamic)
Place a field vertically.
void getPossibleCollisions(std::vector< SCH_ITEM * > &aItems)
Populate a list of all drawing items that may collide with the fields.
static const SIDE SIDE_TOP
static const SIDE SIDE_BOTTOM
unsigned pinsOnSide(SIDE aSide)
Count the number of pins on a side of the symbol.
std::vector< SCH_FIELD * > m_fields
SIDE_AND_NPINS chooseSideForFields(bool aAvoidCollisions)
Look where a symbol's pins are to pick a side to put the fields on.
bool fitFieldsBetweenWires(BOX2I *aBox, SIDE aSide)
Shift a field box up or down a bit to make the fields fit between some wires.
int fieldHPlacement(SCH_FIELD *aField, const BOX2I &aFieldBox)
Place a field horizontally, taking into account the field width and justification.
SCH_SCREEN * m_screen
std::vector< SCH_ITEM * > m_colliders
static const SIDE SIDE_RIGHT
std::vector< SCH_ITEM * > filterCollisions(const BOX2I &aRect)
Filter a list of possible colliders to include only those that actually collide with a given rectangl...
std::vector< SIDE_AND_NPINS > getPreferredSides()
Return a list with the preferred field sides for the symbol, in decreasing order of preference.
std::vector< SIDE_AND_COLL > getCollidingSides()
Return a list of the sides where a field set would collide with another item.
AUTOPLACER(SYMBOL *aSymbol, SCH_SCREEN *aScreen)
static const SIDE SIDE_LEFT
SIDE_AND_NPINS chooseSideFiltered(std::vector< SIDE_AND_NPINS > &aSides, const std::vector< SIDE_AND_COLL > &aCollidingSides, COLLISION aCollision, SIDE_AND_NPINS aLastSelection)
Choose a side for the fields, filtered on only one side collision type.
void DoAutoplace(AUTOPLACE_ALGO aAlgo)
Do the actual autoplacement.
void justifyField(SCH_FIELD *aField, SIDE aFieldSide)
Set the justification of a field based on the side it's supposed to be on, taking into account whethe...
constexpr const Vec & GetPosition() const
Definition box2.h:211
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr Vec Centre() const
Definition box2.h:97
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr coord_type GetTop() const
Definition box2.h:229
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:418
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:199
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:410
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:95
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Automatically orient all the fields in the symbol.
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
bool IsHorizJustifyFlipped() const
Return whether the field will be rendered with the horizontal justification inverted due to rotation ...
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:167
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:743
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
VECTOR2I GetEndPoint() const
Definition sch_line.h:144
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
PIN_ORIENTATION PinDrawOrient(const TRANSFORM &aTransform) const
Return the pin real orientation (PIN_UP, PIN_DOWN, PIN_RIGHT, PIN_LEFT), according to its orientation...
Definition sch_pin.cpp:1149
Schematic symbol object.
Definition sch_symbol.h:75
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Automatically orient all the fields in the symbol.
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:127
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:111
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:118
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:135
AUTOPLACE_ALGO
Definition sch_item.h:68
@ AUTOPLACE_MANUAL
Definition sch_item.h:71
@ AUTOPLACE_AUTO
Definition sch_item.h:70
bool collide(T aObject, U aAnotherObject, int aLayer, int aMinDistance)
Used by SHAPE_INDEX to implement Query().
Definition shape_index.h:97
@ SYM_ORIENT_270
Definition symbol.h:42
@ SYM_ORIENT_180
Definition symbol.h:41
@ SYM_MIRROR_X
Definition symbol.h:43
@ SYM_ORIENT_90
Definition symbol.h:40
@ SYM_ORIENT_0
Definition symbol.h:39
VECTOR2I end
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_CENTER
constexpr GR_TEXT_H_ALIGN_T GetFlippedAlignment(GR_TEXT_H_ALIGN_T aAlign)
Get the reverse alignment: left-right are swapped, others are unchanged.
constexpr GR_TEXT_H_ALIGN_T ToHAlignment(int x)
Convert an integral value to horizontal alignment.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695