KiCad PCB EDA Suite
eeschema/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 (C) 2015, 2020 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 component fields, and
27  * places them there. There are two modes: "auto"-autoplace, and "manual" autoplace.
28  * Auto mode is for when the process is run automatically, like when rotating parts,
29  * and it avoids doing things that would be helpful for the final positioning but
30  * annoying if they 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. ::choose_side_for_fields
35  * 1. Sort the four sides in preference order,
36  * depending on the component's shape and
37  * orientation ::get_preferred_sides
38  * 2. If in manual mode, sift out the sides that would
39  * cause fields to overlap other items ::get_colliding_sides
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 ::field_box_placement
46  * 4. In manual mode, shift the box vertically if possible
47  * to fit fields between adjacent wires ::fit_fields_between_wires
48  * 5. Move all fields to their final positions
49  * 1. Re-justify fields if options allow that ::justify_field
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 <hotkeys_basic.h>
57 #include <sch_component.h>
58 #include <sch_line.h>
59 #include <lib_pin.h>
60 #include <sch_draw_panel.h>
61 #include <class_libentry.h>
62 #include <eeschema_config.h>
63 #include <kiface_i.h>
64 #include <vector>
65 #include <algorithm>
66 #include <tool/tool_manager.h>
68 #include <eeschema_settings.h>
69 
70 #define FIELD_PADDING Mils2iu( 10 ) // arbitrarily chosen for aesthetics
71 #define FIELD_PADDING_ALIGNED Mils2iu( 18 ) // aligns 50 mil text to a 100 mil grid
72 #define WIRE_V_SPACING Mils2iu( 100 )
73 #define HPADDING Mils2iu( 25 )
74 #define VPADDING Mils2iu( 25 )
75 
79 template<typename T> T round_n( const T& value, const T& n, bool aRoundUp )
80 {
81  if( value % n )
82  return n * (value / n + (aRoundUp ? 1 : 0));
83  else
84  return value;
85 }
86 
87 
92 {
93  return static_cast<EDA_TEXT_HJUSTIFY_T>( x );
94 }
95 
96 
98 {
101  std::vector<SCH_FIELD*> m_fields;
102  std::vector<SCH_ITEM*> m_colliders;
104  wxSize m_fbox_size;
107 
108 public:
109  typedef wxPoint SIDE;
112 
114  {
116  unsigned pins;
117  };
118 
120  {
123  };
124 
125 
126  AUTOPLACER( SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen ) :
127  m_screen( aScreen ), m_component( aComponent )
128  {
129  m_component->GetFields( m_fields, /* aVisibleOnly */ true );
130 
131  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
132  wxASSERT( cfg );
133 
134  m_allow_rejustify = false;
135  m_align_to_grid = true;
136 
137  if( cfg )
138  {
139  m_allow_rejustify = cfg->m_AutoplaceFields.allow_rejustify;
140  m_align_to_grid = cfg->m_AutoplaceFields.align_to_grid;
141  }
142 
144  m_fbox_size = ComputeFBoxSize( /* aDynamic */ true );
145 
147 
148  if( aScreen )
150  }
151 
152 
158  void DoAutoplace( bool aManual )
159  {
160  bool force_wire_spacing = false;
161  SIDE field_side = choose_side_for_fields( aManual );
162  wxPoint fbox_pos = field_box_placement( field_side );
163  EDA_RECT field_box( fbox_pos, m_fbox_size );
164 
165  if( aManual )
166  force_wire_spacing = fit_fields_between_wires( &field_box, field_side );
167 
168  // Move the fields
169  int last_y_coord = field_box.GetTop();
170  for( unsigned field_idx = 0; field_idx < m_fields.size(); ++field_idx )
171  {
172  SCH_FIELD* field = m_fields[field_idx];
173 
174  if( m_allow_rejustify )
175  justify_field( field, field_side );
176 
177  wxPoint pos(
178  field_horiz_placement( field, field_box ),
179  field_vert_placement( field, field_box, &last_y_coord, !force_wire_spacing ) );
180 
181  if( m_align_to_grid )
182  {
183  pos.x = round_n( pos.x, Mils2iu( 50 ), field_side.x >= 0 );
184  pos.y = round_n( pos.y, Mils2iu( 50 ), field_side.y == 1 );
185  }
186 
187  field->SetPosition( pos );
188  }
189  }
190 
191 
192 protected:
197  wxSize ComputeFBoxSize( bool aDynamic )
198  {
199  int max_field_width = 0;
200  int total_height = 0;
201 
202  for( SCH_FIELD* field : m_fields )
203  {
204  int field_width;
205  int field_height;
206 
207  if( m_component->GetTransform().y1 )
208  {
209  field->SetTextAngle( TEXT_ANGLE_VERT );
210  }
211  else
212  {
213  field->SetTextAngle( TEXT_ANGLE_HORIZ );
214  }
215 
216  field_width = field->GetBoundingBox().GetWidth();
217  field_height = field->GetBoundingBox().GetHeight();
218 
219  max_field_width = std::max( max_field_width, field_width );
220 
221  if( aDynamic )
222  total_height += field_height + get_field_padding();
223  else
224  total_height += WIRE_V_SPACING;
225 
226  }
227 
228  return wxSize( max_field_width, total_height );
229  }
230 
231 
236  {
237  int pin_orient = aPin->GetLibPin()->PinDrawOrient( m_component->GetTransform() );
238  switch( pin_orient )
239  {
240  case PIN_RIGHT: return SIDE_LEFT;
241  case PIN_LEFT: return SIDE_RIGHT;
242  case PIN_UP: return SIDE_BOTTOM;
243  case PIN_DOWN: return SIDE_TOP;
244  default:
245  wxFAIL_MSG( "Invalid pin orientation" );
246  return SIDE_LEFT;
247  }
248  }
249 
250 
254  unsigned pins_on_side( SIDE aSide )
255  {
256  unsigned pin_count = 0;
257 
258  for( SCH_PIN* each_pin : m_component->GetPins() )
259  {
260  if( !each_pin->IsVisible() && !m_power_symbol )
261  continue;
262  if( get_pin_side( each_pin ) == aSide )
263  ++pin_count;
264  }
265 
266  return pin_count;
267  }
268 
269 
275  void get_possible_colliders( std::vector<SCH_ITEM*>& aItems )
276  {
277  wxCHECK_RET( m_screen, "get_possible_colliders() with null m_screen" );
278 
279  for( auto item : m_screen->Items().Overlapping( m_component->GetBoundingBox() ) )
280  {
281  if( SCH_COMPONENT* comp = dynamic_cast<SCH_COMPONENT*>( item ) )
282  {
283  if( comp == m_component )
284  continue;
285 
286  std::vector<SCH_FIELD*> fields;
287  comp->GetFields( fields, /* aVisibleOnly */ true );
288  for( SCH_FIELD* field : fields )
289  aItems.push_back( field );
290  }
291 
292  aItems.push_back( item );
293  }
294  }
295 
296 
301  std::vector<SCH_ITEM*> filtered_colliders( const EDA_RECT& aRect )
302  {
303  std::vector<SCH_ITEM*> filtered;
304  for( SCH_ITEM* item : m_colliders )
305  {
306  EDA_RECT item_box;
307  if( SCH_COMPONENT* item_comp = dynamic_cast<SCH_COMPONENT*>( item ) )
308  item_box = item_comp->GetBodyBoundingBox();
309  else
310  item_box = item->GetBoundingBox();
311 
312  if( item_box.Intersects( aRect ) )
313  filtered.push_back( item );
314  }
315  return filtered;
316  }
317 
318 
323  std::vector<SIDE_AND_NPINS> get_preferred_sides()
324  {
325  SIDE_AND_NPINS sides_init[] = {
330  };
331  std::vector<SIDE_AND_NPINS> sides( sides_init, sides_init + arrayDim( sides_init ) );
332 
333  int orient = m_component->GetOrientation();
334  int orient_angle = orient & 0xff; // enum is a bitmask
335  bool h_mirrored = ( ( orient & CMP_MIRROR_X )
336  && ( orient_angle == CMP_ORIENT_0 || orient_angle == CMP_ORIENT_180 ) );
337  double w = double( m_comp_bbox.GetWidth() );
338  double h = double( m_comp_bbox.GetHeight() );
339 
340  // The preferred-sides heuristics are a bit magical. These were determined mostly
341  // by trial and error.
342 
343  if( m_power_symbol )
344  {
345  // For power symbols, we generally want the label at the top first.
346  switch( orient_angle )
347  {
348  case CMP_ORIENT_0:
349  std::swap( sides[0], sides[1] );
350  std::swap( sides[1], sides[3] );
351  // TOP, BOTTOM, RIGHT, LEFT
352  break;
353  case CMP_ORIENT_90:
354  std::swap( sides[0], sides[2] );
355  std::swap( sides[1], sides[2] );
356  // LEFT, RIGHT, TOP, BOTTOM
357  break;
358  case CMP_ORIENT_180:
359  std::swap( sides[0], sides[3] );
360  // BOTTOM, TOP, LEFT, RIGHT
361  break;
362  case CMP_ORIENT_270:
363  std::swap( sides[1], sides[2] );
364  // RIGHT, LEFT, TOP, BOTTOM
365  break;
366  }
367  }
368  else
369  {
370  // If the component is horizontally mirrored, swap left and right
371  if( h_mirrored )
372  {
373  std::swap( sides[0], sides[2] );
374  }
375 
376  // If the component is very long or is a power symbol, swap H and V
377  if( w/h > 3.0 )
378  {
379  std::swap( sides[0], sides[1] );
380  std::swap( sides[1], sides[3] );
381  }
382  }
383 
384  return sides;
385  }
386 
387 
391  std::vector<SIDE_AND_COLL> get_colliding_sides()
392  {
393  SIDE sides_init[] = { SIDE_RIGHT, SIDE_TOP, SIDE_LEFT, SIDE_BOTTOM };
394  std::vector<SIDE> sides( sides_init, sides_init + arrayDim( sides_init ) );
395  std::vector<SIDE_AND_COLL> colliding;
396 
397  // Iterate over all sides and find the ones that collide
398  for( SIDE side : sides )
399  {
400  EDA_RECT box( field_box_placement( side ), m_fbox_size );
401 
402  COLLISION collision = COLLIDE_NONE;
403  for( SCH_ITEM* collider : filtered_colliders( box ) )
404  {
405  SCH_LINE* line = dynamic_cast<SCH_LINE*>( collider );
406  if( line && !side.x )
407  {
408  wxPoint start = line->GetStartPoint(), end = line->GetEndPoint();
409  if( start.y == end.y && collision != COLLIDE_OBJECTS )
410  collision = COLLIDE_H_WIRES;
411  else
412  collision = COLLIDE_OBJECTS;
413  }
414  else
415  collision = COLLIDE_OBJECTS;
416  }
417 
418  if( collision != COLLIDE_NONE )
419  colliding.push_back( { side, collision } );
420  }
421 
422  return colliding;
423  }
424 
425 
430  SIDE_AND_NPINS choose_side_filtered( std::vector<SIDE_AND_NPINS>& aSides,
431  const std::vector<SIDE_AND_COLL>& aCollidingSides, COLLISION aCollision,
432  SIDE_AND_NPINS aLastSelection)
433  {
434  SIDE_AND_NPINS sel = aLastSelection;
435 
436  std::vector<SIDE_AND_NPINS>::iterator it = aSides.begin();
437  while( it != aSides.end() )
438  {
439  bool collide = false;
440  for( SIDE_AND_COLL collision : aCollidingSides )
441  {
442  if( collision.side == it->side && collision.collision == aCollision )
443  collide = true;
444  }
445  if( !collide )
446  ++it;
447  else
448  {
449  if( it->pins <= sel.pins )
450  {
451  sel.pins = it->pins;
452  sel.side = it->side;
453  }
454  it = aSides.erase( it );
455  }
456  }
457  return sel;
458  }
459 
460 
466  SIDE choose_side_for_fields( bool aAvoidCollisions )
467  {
468  std::vector<SIDE_AND_NPINS> sides = get_preferred_sides();
469 
470  std::reverse( sides.begin(), sides.end() );
471  SIDE_AND_NPINS side = { wxPoint( 1, 0 ), UINT_MAX };
472 
473  if( aAvoidCollisions )
474  {
475  std::vector<SIDE_AND_COLL> colliding_sides = get_colliding_sides();
476  side = choose_side_filtered( sides, colliding_sides, COLLIDE_OBJECTS, side );
477  side = choose_side_filtered( sides, colliding_sides, COLLIDE_H_WIRES, side );
478  }
479 
480  for( SIDE_AND_NPINS& each_side : sides | boost::adaptors::reversed )
481  {
482  if( !each_side.pins ) return each_side.side;
483  }
484 
485  for( SIDE_AND_NPINS& each_side : sides )
486  {
487  if( each_side.pins <= side.pins )
488  {
489  side.pins = each_side.pins;
490  side.side = each_side.side;
491  }
492  }
493 
494  return side.side;
495  }
496 
497 
503  void justify_field( SCH_FIELD* aField, SIDE aFieldSide )
504  {
505  // Justification is set twice to allow IsHorizJustifyFlipped() to work correctly.
506  aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x ) );
507  aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x *
508  ( aField->IsHorizJustifyFlipped() ? -1 : 1 ) ) );
510  }
511 
512 
517  {
518  wxPoint fbox_center = m_comp_bbox.Centre();
519  int offs_x = ( m_comp_bbox.GetWidth() + m_fbox_size.GetWidth() ) / 2 + HPADDING;
520  int offs_y = ( m_comp_bbox.GetHeight() + m_fbox_size.GetHeight() ) / 2 + VPADDING;
521 
522  fbox_center.x += aFieldSide.x * offs_x;
523  fbox_center.y += aFieldSide.y * offs_y;
524 
525  wxPoint fbox_pos(
526  fbox_center.x - m_fbox_size.GetWidth() / 2,
527  fbox_center.y - m_fbox_size.GetHeight() / 2 );
528 
529  return fbox_pos;
530  }
531 
532 
538  {
539  if( aSide != SIDE_TOP && aSide != SIDE_BOTTOM )
540  return false;
541 
542  std::vector<SCH_ITEM*> colliders = filtered_colliders( *aBox );
543  if( colliders.empty() )
544  return false;
545 
546  // Find the offset of the wires for proper positioning
547  int offset = 0;
548 
549  for( SCH_ITEM* item : colliders )
550  {
551  SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
552  if( !line )
553  return false;
554  wxPoint start = line->GetStartPoint(), end = line->GetEndPoint();
555  if( start.y != end.y )
556  return false;
557 
558  int this_offset = (3 * WIRE_V_SPACING / 2) - ( start.y % WIRE_V_SPACING );
559  if( offset == 0 )
560  offset = this_offset;
561  else if( offset != this_offset )
562  return false;
563  }
564 
565  // At this point we are recomputing the field box size. Do not
566  // return false after this point.
567  m_fbox_size = ComputeFBoxSize( /* aDynamic */ false );
568 
569  wxPoint pos = aBox->GetPosition();
570 
571  // Remove the existing padding to get a bit more space to work with
572  if( aSide == SIDE_BOTTOM )
573  {
575  }
576  else
577  {
579  }
580 
581  pos.y = round_n( pos.y, WIRE_V_SPACING, aSide == SIDE_BOTTOM );
582 
583  aBox->SetOrigin( pos );
584  return true;
585  }
586 
587 
596  int field_horiz_placement( SCH_FIELD *aField, const EDA_RECT &aFieldBox )
597  {
598  int field_hjust;
599  int field_xcoord;
600 
601  if( aField->IsHorizJustifyFlipped() )
602  field_hjust = -aField->GetHorizJustify();
603  else
604  field_hjust = aField->GetHorizJustify();
605 
606  switch( field_hjust )
607  {
609  field_xcoord = aFieldBox.GetLeft();
610  break;
612  field_xcoord = aFieldBox.Centre().x;
613  break;
615  field_xcoord = aFieldBox.GetRight();
616  break;
617  default:
618  wxFAIL_MSG( "Unexpected value for SCH_FIELD::GetHorizJustify()" );
619  field_xcoord = aFieldBox.Centre().x; // Most are centered
620  }
621 
622  return field_xcoord;
623  }
624 
636  int field_vert_placement( SCH_FIELD *aField, const EDA_RECT &aFieldBox, int *aPosAccum,
637  bool aDynamic )
638  {
639  int field_height;
640  int padding;
641 
642  if( aDynamic )
643  {
644  field_height = aField->GetBoundingBox().GetHeight();
645 
646  padding = get_field_padding();
647  }
648  else
649  {
650  field_height = WIRE_V_SPACING / 2;
651  padding = WIRE_V_SPACING / 2;
652  }
653 
654  int placement = *aPosAccum + padding / 2 + field_height / 2;
655 
656  *aPosAccum += padding + field_height;
657 
658  return placement;
659  }
660 
665  {
666  if( m_align_to_grid )
667  return FIELD_PADDING_ALIGNED;
668  else
669  return FIELD_PADDING;
670  }
671 
672 };
673 
678 
679 
680 void SCH_COMPONENT::AutoplaceFields( SCH_SCREEN* aScreen, bool aManual )
681 {
682  if( aManual )
683  wxASSERT_MSG( aScreen, "A SCH_SCREEN pointer must be given for manual autoplacement" );
684 
685  AUTOPLACER autoplacer( this, aScreen );
686  autoplacer.DoAutoplace( aManual );
688 }
void justify_field(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...
#define TEXT_ANGLE_HORIZ
Frequent text rotations, used with {Set,Get}TextAngle(), in 0.1 degrees for now, hoping to migrate to...
Definition: common.h:185
SCH_FIELD instances are attached to a component and provide a place for the component's value,...
Definition: sch_field.h:52
LIB_PIN * GetLibPin() const
Definition: sch_pin.h:67
wxSize ComputeFBoxSize(bool aDynamic)
Compute and return the size of the fields' bounding box.
unsigned pins_on_side(SIDE aSide)
Count the number of pins on a side of the component.
std::vector< SCH_FIELD * > m_fields
EDA_TEXT_HJUSTIFY_T
Definition: eda_text.h:48
std::vector< SIDE_AND_COLL > get_colliding_sides()
Return a list of the sides where a field set would collide with another item.
int GetOrientation()
Get the display symbol orientation.
wxPoint GetStartPoint() const
Definition: sch_line.h:94
bool collide(T aObject, U aAnotherObject, int aMinDistance)
collide template method
Definition: shape_index.h:92
int GetTop() const
Definition: eda_rect.h:123
int GetLeft() const
Definition: eda_rect.h:122
#define WIRE_V_SPACING
EE_TYPE Overlapping(const EDA_RECT &aRect)
Definition: sch_rtree.h:224
SCH_COMPONENT * m_component
#define VPADDING
int GetWidth() const
Definition: eda_rect.h:119
SIDE_AND_NPINS choose_side_filtered(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.
bool IsInNetlist() const
wxPoint field_box_placement(SIDE aFieldSide)
Return the position of the field bounding box.
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:131
Definition: lib_pin.h:50
int PinDrawOrient(const TRANSFORM &aTransform) const
Return the pin real orientation (PIN_UP, PIN_DOWN, PIN_RIGHT, PIN_LEFT), according to its orientation...
Definition: lib_pin.cpp:800
#define TEXT_ANGLE_VERT
Definition: common.h:186
#define HPADDING
FIELDS_AUTOPLACED m_fieldsAutoplaced
Definition: sch_item.h:201
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populates a std::vector with SCH_FIELDs.
int GetBottom() const
Definition: eda_rect.h:124
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
bool fit_fields_between_wires(EDA_RECT *aBox, SIDE aSide)
Shift a field box up or down a bit to make the fields fit between some wires.
int field_horiz_placement(SCH_FIELD *aField, const EDA_RECT &aFieldBox)
Place a field horizontally, taking into account the field width and justification.
int y1
Definition: transform.h:49
static const SIDE SIDE_LEFT
SIDE get_pin_side(SCH_PIN *aPin)
Return the side that a pin is on.
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:199
std::vector< SCH_ITEM * > m_colliders
TRANSFORM & GetTransform() const
EDA_RECT GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the fields.
int field_vert_placement(SCH_FIELD *aField, const EDA_RECT &aFieldBox, int *aPosAccum, bool aDynamic)
Place a field vertically.
EDA_TEXT_HJUSTIFY_T TO_HJUSTIFY(int x)
Convert an integer to a horizontal justification; neg=L zero=C pos=R.
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:203
const wxPoint GetPosition() const
Definition: eda_rect.h:115
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
int GetRight() const
Definition: eda_rect.h:121
int GetHeight() const
Definition: eda_rect.h:120
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieves a list of the SCH_PINs for the given sheet path.
static const SIDE SIDE_RIGHT
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Definition: macros.h:160
T round_n(const T &value, const T &n, bool aRoundUp)
Round up/down to the nearest multiple of n.
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes.
Definition: sch_field.cpp:252
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:202
static const SIDE SIDE_BOTTOM
int get_field_padding()
Return the desired padding between fields.
EE_RTREE & Items()
Definition: sch_screen.h:158
EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Automatically orient all the fields in the component.
Schematic symbol object.
Definition: sch_component.h:80
wxPoint Centre() const
Definition: eda_rect.h:62
bool IsHorizJustifyFlipped() const
Function IsHorizJustifyFlipped Returns whether the field will be rendered with the horizontal justifi...
Definition: sch_field.cpp:294
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
#define FIELD_PADDING
SIDE choose_side_for_fields(bool aAvoidCollisions)
Look where a component's pins are to pick a side to put the fields on.
void DoAutoplace(bool aManual)
Do the actual autoplacement.
#define FIELD_PADDING_ALIGNED
static const SIDE SIDE_TOP
std::vector< SIDE_AND_NPINS > get_preferred_sides()
Return a list with the preferred field sides for the component, in decreasing order of preference.
AUTOPLACER(SCH_COMPONENT *aComponent, SCH_SCREEN *aScreen)
void get_possible_colliders(std::vector< SCH_ITEM * > &aItems)
Populate a list of all drawing items that may collide with the fields.
void SetPosition(const wxPoint &aPosition) override
Definition: sch_field.cpp:578
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:194
std::vector< SCH_ITEM * > filtered_colliders(const EDA_RECT &aRect)
Filter a list of possible colliders to include only those that actually collide with a given rectangl...
wxPoint GetEndPoint() const
Definition: sch_line.h:97