KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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 <pavlina.chris@gmail.com>
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
93 {
96 };
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
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 {
230 case PIN_ORIENTATION::PIN_RIGHT: return SIDE_LEFT;
231 case PIN_ORIENTATION::PIN_LEFT: return SIDE_RIGHT;
232 case PIN_ORIENTATION::PIN_UP: return SIDE_BOTTOM;
233 case PIN_ORIENTATION::PIN_DOWN: return SIDE_TOP;
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
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:110
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
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
VECTOR2I m_fbox_size
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:410
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:187
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:402
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:246
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.
Definition: sch_field.cpp:499
bool IsHorizJustifyFlipped() const
Return whether the field will be rendered with the horizontal justification inverted due to rotation ...
Definition: sch_field.cpp:527
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:710
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:41
VECTOR2I GetEndPoint() const
Definition: sch_line.h:143
VECTOR2I GetStartPoint() const
Definition: sch_line.h:138
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:968
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:112
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
virtual BOX2I GetBodyAndPinsBoundingBox() const =0
Return a bounding box for the symbol body and pins but not the fields.
virtual void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly) const =0
const TRANSFORM & GetTransform() const
Definition: symbol.h:197
virtual BOX2I GetBodyBoundingBox() const =0
Return a bounding box for the symbol body but not the pins or fields.
virtual std::vector< SCH_PIN * > GetPins() const =0
virtual int GetOrientation() const
Definition: symbol.h:195
int y1
Definition: transform.h:49
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition: eda_angle.h:398
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition: eda_angle.h:397
PIN_ORIENTATION
The symbol library pin object orientations.
Definition: pin_type.h:80
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
constexpr int MilsToIU(int mils) const
Definition: base_units.h:93
@ 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