KiCad PCB EDA Suite
AUTOPLACER Class Reference

Classes

struct  SIDE_AND_COLL
 
struct  SIDE_AND_NPINS
 

Public Types

enum  COLLISION { COLLIDE_NONE, COLLIDE_OBJECTS, COLLIDE_H_WIRES }
 
typedef wxPoint SIDE
 

Public Member Functions

 AUTOPLACER (SCH_SYMBOL *aSymbol, SCH_SCREEN *aScreen)
 
void DoAutoplace (bool aManual)
 Do the actual autoplacement. More...
 

Static Public Attributes

static const SIDE SIDE_TOP
 
static const SIDE SIDE_BOTTOM
 
static const SIDE SIDE_LEFT
 
static const SIDE SIDE_RIGHT
 

Protected Member Functions

wxSize computeFBoxSize (bool aDynamic)
 Compute and return the size of the fields' bounding box. More...
 
SIDE getPinSide (SCH_PIN *aPin)
 Return the side that a pin is on. More...
 
unsigned pinsOnSide (SIDE aSide)
 Count the number of pins on a side of the symbol. More...
 
void getPossibleCollisions (std::vector< SCH_ITEM * > &aItems)
 Populate a list of all drawing items that may collide with the fields. More...
 
std::vector< SCH_ITEM * > filterCollisions (const EDA_RECT &aRect)
 Filter a list of possible colliders to include only those that actually collide with a given rectangle. More...
 
std::vector< SIDE_AND_NPINSgetPreferredSides ()
 Return a list with the preferred field sides for the symbol, in decreasing order of preference. More...
 
std::vector< SIDE_AND_COLLgetCollidingSides ()
 Return a list of the sides where a field set would collide with another item. More...
 
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. More...
 
SIDE_AND_NPINS chooseSideForFields (bool aAvoidCollisions)
 Look where a symbol's pins are to pick a side to put the fields on. More...
 
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 whether the field will be displayed with flipped justification due to mirroring. More...
 
wxPoint fieldBoxPlacement (SIDE_AND_NPINS aFieldSideAndPins)
 Return the position of the field bounding box. More...
 
bool fitFieldsBetweenWires (EDA_RECT *aBox, SIDE aSide)
 Shift a field box up or down a bit to make the fields fit between some wires. More...
 
int fieldHorizPlacement (SCH_FIELD *aField, const EDA_RECT &aFieldBox)
 Place a field horizontally, taking into account the field width and justification. More...
 
int fieldVertPlacement (SCH_FIELD *aField, const EDA_RECT &aFieldBox, int *aPosAccum, bool aDynamic)
 Place a field vertically. More...
 

Private Attributes

SCH_SCREENm_screen
 
SCH_SYMBOLm_symbol
 
std::vector< SCH_FIELD * > m_fields
 
std::vector< SCH_ITEM * > m_colliders
 
EDA_RECT m_symbol_bbox
 
wxSize m_fbox_size
 
bool m_allow_rejustify
 
bool m_align_to_grid
 
bool m_is_power_symbol
 

Detailed Description

Definition at line 94 of file autoplace_fields.cpp.

Member Typedef Documentation

◆ SIDE

typedef wxPoint AUTOPLACER::SIDE

Definition at line 97 of file autoplace_fields.cpp.

Member Enumeration Documentation

◆ COLLISION

Constructor & Destructor Documentation

◆ AUTOPLACER()

AUTOPLACER::AUTOPLACER ( SCH_SYMBOL aSymbol,
SCH_SCREEN aScreen 
)
inline

Definition at line 113 of file autoplace_fields.cpp.

113  :
114  m_screen( aScreen ),
115  m_symbol( aSymbol )
116  {
117  m_symbol->GetFields( m_fields, /* aVisibleOnly */ true );
118 
119  auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
120  wxASSERT( cfg );
121 
122  m_allow_rejustify = false;
123  m_align_to_grid = true;
124 
125  if( cfg )
126  {
127  m_allow_rejustify = cfg->m_AutoplaceFields.allow_rejustify;
128  m_align_to_grid = cfg->m_AutoplaceFields.align_to_grid;
129  }
130 
132  m_fbox_size = computeFBoxSize( /* aDynamic */ true );
133 
135 
136  if( aScreen )
138  }
std::vector< SCH_FIELD * > m_fields
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:711
EDA_RECT m_symbol_bbox
bool IsInNetlist() const
SCH_SCREEN * m_screen
std::vector< SCH_ITEM * > m_colliders
wxSize computeFBoxSize(bool aDynamic)
Compute and return the size of the fields' bounding box.
EDA_RECT GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the pins or fields.
SCH_SYMBOL * m_symbol
void getPossibleCollisions(std::vector< SCH_ITEM * > &aItems)
Populate a list of all drawing items that may collide with the fields.

References computeFBoxSize(), SCH_SYMBOL::GetBodyBoundingBox(), SCH_SYMBOL::GetFields(), getPossibleCollisions(), SCH_SYMBOL::IsInNetlist(), Kiface(), m_align_to_grid, m_allow_rejustify, m_colliders, m_fbox_size, m_fields, m_is_power_symbol, m_symbol, and m_symbol_bbox.

Member Function Documentation

◆ chooseSideFiltered()

SIDE_AND_NPINS AUTOPLACER::chooseSideFiltered ( std::vector< SIDE_AND_NPINS > &  aSides,
const std::vector< SIDE_AND_COLL > &  aCollidingSides,
COLLISION  aCollision,
SIDE_AND_NPINS  aLastSelection 
)
inlineprotected

Choose a side for the fields, filtered on only one side collision type.

Removes the sides matching the filter from the list.

Definition at line 446 of file autoplace_fields.cpp.

450  {
451  SIDE_AND_NPINS sel = aLastSelection;
452 
453  std::vector<SIDE_AND_NPINS>::iterator it = aSides.begin();
454 
455  while( it != aSides.end() )
456  {
457  bool collide = false;
458 
459  for( SIDE_AND_COLL collision : aCollidingSides )
460  {
461  if( collision.side == it->side && collision.collision == aCollision )
462  collide = true;
463  }
464 
465  if( !collide )
466  {
467  ++it;
468  }
469  else
470  {
471  if( it->pins <= sel.pins )
472  {
473  sel.pins = it->pins;
474  sel.side = it->side;
475  }
476 
477  it = aSides.erase( it );
478  }
479  }
480 
481  return sel;
482  }
bool collide(T aObject, U aAnotherObject, int aMinDistance)
Used by SHAPE_INDEX to implement Query().
Definition: shape_index.h:114

References collide(), AUTOPLACER::SIDE_AND_NPINS::pins, and AUTOPLACER::SIDE_AND_NPINS::side.

Referenced by chooseSideForFields().

◆ chooseSideForFields()

SIDE_AND_NPINS AUTOPLACER::chooseSideForFields ( bool  aAvoidCollisions)
inlineprotected

Look where a symbol's pins are to pick a side to put the fields on.

Parameters
aAvoidCollisions- if true, pick last the sides where the label will collide with other items.

Definition at line 489 of file autoplace_fields.cpp.

490  {
491  std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
492 
493  std::reverse( sides.begin(), sides.end() );
494  SIDE_AND_NPINS side = { wxPoint( 1, 0 ), UINT_MAX };
495 
496  if( aAvoidCollisions )
497  {
498  std::vector<SIDE_AND_COLL> colliding_sides = getCollidingSides();
499  side = chooseSideFiltered( sides, colliding_sides, COLLIDE_OBJECTS, side );
500  side = chooseSideFiltered( sides, colliding_sides, COLLIDE_H_WIRES, side );
501  }
502 
503  for( SIDE_AND_NPINS& each_side : sides | boost::adaptors::reversed )
504  {
505  if( !each_side.pins ) return each_side;
506  }
507 
508  for( SIDE_AND_NPINS& each_side : sides )
509  {
510  if( each_side.pins <= side.pins )
511  {
512  side.pins = each_side.pins;
513  side.side = each_side.side;
514  }
515  }
516 
517  return side;
518  }
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.
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.

References chooseSideFiltered(), COLLIDE_H_WIRES, COLLIDE_OBJECTS, getCollidingSides(), and getPreferredSides().

Referenced by DoAutoplace().

◆ computeFBoxSize()

wxSize AUTOPLACER::computeFBoxSize ( bool  aDynamic)
inlineprotected

Compute and return the size of the fields' bounding box.

Parameters
aDynamic- if true, use dynamic spacing

Definition at line 199 of file autoplace_fields.cpp.

200  {
201  int max_field_width = 0;
202  int total_height = 0;
203 
204  for( SCH_FIELD* field : m_fields )
205  {
206  if( m_symbol->GetTransform().y1 )
207  field->SetTextAngle( TEXT_ANGLE_VERT );
208  else
209  field->SetTextAngle( TEXT_ANGLE_HORIZ );
210 
211  EDA_RECT bbox = field->GetBoundingBox();
212  int field_width = bbox.GetWidth();
213  int field_height = bbox.GetHeight();
214 
215  max_field_width = std::max( max_field_width, field_width );
216 
217  // Remove interline spacing from field_height for last line.
218  if( field == m_fields[ m_fields.size() - 1 ] )
219  field_height *= 0.62;
220 
221  if( !aDynamic )
222  total_height += WIRE_V_SPACING;
223  else if( m_align_to_grid )
224  total_height += round_n( field_height, Mils2iu( 50 ), true );
225  else
226  total_height += field_height + FIELD_PADDING;
227  }
228 
229  return wxSize( max_field_width, total_height );
230  }
#define TEXT_ANGLE_HORIZ
Frequent text rotations, used with {Set,Get}TextAngle(), in 0.1 degrees for now, hoping to migrate to...
Definition: eda_text.h:71
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:49
std::vector< SCH_FIELD * > m_fields
int GetWidth() const
Definition: eda_rect.h:109
TRANSFORM & GetTransform()
Definition: sch_symbol.h:231
#define WIRE_V_SPACING
T round_n(const T &value, const T &n, bool aRoundUp)
Round up/down to the nearest multiple of n.
int y1
Definition: transform.h:49
#define FIELD_PADDING
SCH_SYMBOL * m_symbol
int GetHeight() const
Definition: eda_rect.h:110
Handle the component boundary box.
Definition: eda_rect.h:42
#define TEXT_ANGLE_VERT
Definition: eda_text.h:72

References FIELD_PADDING, EDA_RECT::GetHeight(), SCH_SYMBOL::GetTransform(), EDA_RECT::GetWidth(), m_align_to_grid, m_fields, m_symbol, round_n(), TEXT_ANGLE_HORIZ, TEXT_ANGLE_VERT, WIRE_V_SPACING, and TRANSFORM::y1.

Referenced by AUTOPLACER(), and fitFieldsBetweenWires().

◆ DoAutoplace()

void AUTOPLACER::DoAutoplace ( bool  aManual)
inline

Do the actual autoplacement.

Parameters
aManual- if true, use extra heuristics for smarter placement when manually called up.

Definition at line 145 of file autoplace_fields.cpp.

146  {
147  bool force_wire_spacing = false;
148  SIDE_AND_NPINS sideandpins = chooseSideForFields( aManual );
149  SIDE field_side = sideandpins.side;
150  wxPoint fbox_pos = fieldBoxPlacement( sideandpins );
151  EDA_RECT field_box( fbox_pos, m_fbox_size );
152 
153  if( aManual )
154  force_wire_spacing = fitFieldsBetweenWires( &field_box, field_side );
155 
156  // Move the fields
157  int last_y_coord = field_box.GetTop();
158 
159  for( unsigned field_idx = 0; field_idx < m_fields.size(); ++field_idx )
160  {
161  SCH_FIELD* field = m_fields[field_idx];
162 
163  if( m_allow_rejustify )
164  {
165  if( sideandpins.pins > 0 )
166  {
167  if( field_side == SIDE_TOP || field_side == SIDE_BOTTOM )
168  justifyField( field, SIDE_RIGHT );
169  else
170  justifyField( field, SIDE_TOP );
171  }
172  else
173  {
174  justifyField( field, field_side );
175  }
176  }
177 
178  wxPoint pos( fieldHorizPlacement( field, field_box ),
179  fieldVertPlacement( field, field_box, &last_y_coord, !force_wire_spacing ) );
180 
181  if( m_align_to_grid )
182  {
183  if( abs( field_side.x ) > 0 )
184  pos.x = round_n( pos.x, Mils2iu( 50 ), field_side.x >= 0 );
185 
186  if( abs( field_side.y ) > 0 )
187  pos.y = round_n( pos.y, Mils2iu( 50 ), field_side.y >= 0 );
188  }
189 
190  field->SetPosition( pos );
191  }
192  }
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:49
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(EDA_RECT *aBox, SIDE aSide)
Shift a field box up or down a bit to make the fields fit between some wires.
int fieldHorizPlacement(SCH_FIELD *aField, const EDA_RECT &aFieldBox)
Place a field horizontally, taking into account the field width and justification.
T round_n(const T &value, const T &n, bool aRoundUp)
Round up/down to the nearest multiple of n.
int fieldVertPlacement(SCH_FIELD *aField, const EDA_RECT &aFieldBox, int *aPosAccum, bool aDynamic)
Place a field vertically.
static const SIDE SIDE_RIGHT
static const SIDE SIDE_BOTTOM
wxPoint fieldBoxPlacement(SIDE_AND_NPINS aFieldSideAndPins)
Return the position of the field bounding box.
Handle the component boundary box.
Definition: eda_rect.h:42
static const SIDE SIDE_TOP
void SetPosition(const wxPoint &aPosition) override
Definition: sch_field.cpp:822
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...

References chooseSideForFields(), fieldBoxPlacement(), fieldHorizPlacement(), fieldVertPlacement(), fitFieldsBetweenWires(), EDA_RECT::GetTop(), justifyField(), m_align_to_grid, m_allow_rejustify, m_fbox_size, m_fields, AUTOPLACER::SIDE_AND_NPINS::pins, round_n(), SCH_FIELD::SetPosition(), AUTOPLACER::SIDE_AND_NPINS::side, SIDE_BOTTOM, SIDE_RIGHT, and SIDE_TOP.

Referenced by SCH_SYMBOL::AutoplaceFields().

◆ fieldBoxPlacement()

wxPoint AUTOPLACER::fieldBoxPlacement ( SIDE_AND_NPINS  aFieldSideAndPins)
inlineprotected

Return the position of the field bounding box.

Definition at line 537 of file autoplace_fields.cpp.

538  {
539  wxPoint fbox_center = m_symbol_bbox.Centre();
540  int offs_x = ( m_symbol_bbox.GetWidth() + m_fbox_size.GetWidth() ) / 2;
541  int offs_y = ( m_symbol_bbox.GetHeight() + m_fbox_size.GetHeight() ) / 2;
542 
543  if( aFieldSideAndPins.side.x != 0 )
544  offs_x += HPADDING;
545  else if( aFieldSideAndPins.side.y != 0 )
546  offs_y += VPADDING;
547 
548  fbox_center.x += aFieldSideAndPins.side.x * offs_x;
549  fbox_center.y += aFieldSideAndPins.side.y * offs_y;
550 
551  int x = fbox_center.x - ( m_fbox_size.GetWidth() / 2 );
552  int y = fbox_center.y - ( m_fbox_size.GetHeight() / 2 );
553 
554  auto getPinsBox =
555  [&]( const wxPoint& aSide )
556  {
557  EDA_RECT pinsBox;
558 
559  for( SCH_PIN* each_pin : m_symbol->GetPins() )
560  {
561  if( !each_pin->IsVisible() && !m_is_power_symbol )
562  continue;
563 
564  if( getPinSide( each_pin ) == aSide )
565  pinsBox.Merge( each_pin->GetBoundingBox() );
566  }
567 
568  return pinsBox;
569  };
570 
571  if( aFieldSideAndPins.pins > 0 )
572  {
573  EDA_RECT pinsBox = getPinsBox( aFieldSideAndPins.side );
574 
575  if( aFieldSideAndPins.side == SIDE_TOP || aFieldSideAndPins.side == SIDE_BOTTOM )
576  {
577  x = pinsBox.GetRight() + ( HPADDING * 2 );
578  }
579  else if( aFieldSideAndPins.side == SIDE_RIGHT || aFieldSideAndPins.side == SIDE_LEFT )
580  {
581  y = pinsBox.GetTop() - ( m_fbox_size.GetHeight() + ( VPADDING * 2 ) );
582  }
583  }
584 
585  return wxPoint( x, y );
586  }
#define VPADDING
void Merge(const EDA_RECT &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: eda_rect.cpp:432
int GetTop() const
Definition: eda_rect.h:113
#define HPADDING
int GetWidth() const
Definition: eda_rect.h:109
EDA_RECT m_symbol_bbox
SIDE getPinSide(SCH_PIN *aPin)
Return the side that a pin is on.
static const SIDE SIDE_LEFT
int GetRight() const
Definition: eda_rect.h:111
SCH_SYMBOL * m_symbol
int GetHeight() const
Definition: eda_rect.h:110
static const SIDE SIDE_RIGHT
static const SIDE SIDE_BOTTOM
Handle the component boundary box.
Definition: eda_rect.h:42
wxPoint Centre() const
Definition: eda_rect.h:55
static const SIDE SIDE_TOP
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:866

References EDA_RECT::Centre(), EDA_RECT::GetHeight(), SCH_SYMBOL::GetPins(), getPinSide(), EDA_RECT::GetRight(), EDA_RECT::GetTop(), EDA_RECT::GetWidth(), HPADDING, m_fbox_size, m_is_power_symbol, m_symbol, m_symbol_bbox, EDA_RECT::Merge(), AUTOPLACER::SIDE_AND_NPINS::pins, AUTOPLACER::SIDE_AND_NPINS::side, SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT, SIDE_TOP, and VPADDING.

Referenced by DoAutoplace(), getCollidingSides(), and getPossibleCollisions().

◆ fieldHorizPlacement()

int AUTOPLACER::fieldHorizPlacement ( SCH_FIELD aField,
const EDA_RECT aFieldBox 
)
inlineprotected

Place a field horizontally, taking into account the field width and justification.

Parameters
aField- the field to place.
aFieldBox- box in which fields will be placed
Returns
Correct field horizontal position

Definition at line 645 of file autoplace_fields.cpp.

646  {
647  int field_hjust;
648  int field_xcoord;
649 
650  if( aField->IsHorizJustifyFlipped() )
651  field_hjust = -aField->GetHorizJustify();
652  else
653  field_hjust = aField->GetHorizJustify();
654 
655  switch( field_hjust )
656  {
658  field_xcoord = aFieldBox.GetLeft();
659  break;
661  field_xcoord = aFieldBox.Centre().x;
662  break;
664  field_xcoord = aFieldBox.GetRight();
665  break;
666  default:
667  wxFAIL_MSG( "Unexpected value for SCH_FIELD::GetHorizJustify()" );
668  field_xcoord = aFieldBox.Centre().x; // Most are centered
669  }
670 
671  return field_xcoord;
672  }
int GetLeft() const
Definition: eda_rect.h:112
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:219
int GetRight() const
Definition: eda_rect.h:111
wxPoint Centre() const
Definition: eda_rect.h:55
bool IsHorizJustifyFlipped() const
Return whether the field will be rendered with the horizontal justification inverted due to rotation ...
Definition: sch_field.cpp:347

References EDA_RECT::Centre(), EDA_TEXT::GetHorizJustify(), EDA_RECT::GetLeft(), EDA_RECT::GetRight(), GR_TEXT_HJUSTIFY_CENTER, GR_TEXT_HJUSTIFY_LEFT, GR_TEXT_HJUSTIFY_RIGHT, and SCH_FIELD::IsHorizJustifyFlipped().

Referenced by DoAutoplace().

◆ fieldVertPlacement()

int AUTOPLACER::fieldVertPlacement ( SCH_FIELD aField,
const EDA_RECT aFieldBox,
int *  aPosAccum,
bool  aDynamic 
)
inlineprotected

Place a field vertically.

Because field vertical placements accumulate, this takes a pointer to a vertical position accumulator.

Parameters
aField- the field to place.
aFieldBox- box in which fields will be placed.
aPosAccum- pointer to a position accumulator
aDynamic- use dynamic spacing
Returns
Correct field vertical position

Definition at line 685 of file autoplace_fields.cpp.

687  {
688  int field_height;
689  int padding;
690 
691  if( !aDynamic )
692  {
693  field_height = WIRE_V_SPACING / 2;
694  padding = WIRE_V_SPACING / 2;
695  }
696  else if( m_align_to_grid )
697  {
698  field_height = aField->GetBoundingBox().GetHeight();
699  padding = round_n( field_height, Mils2iu( 50 ), true ) - field_height;
700  }
701  else
702  {
703  field_height = aField->GetBoundingBox().GetHeight();
704  padding = FIELD_PADDING;
705  }
706 
707  int placement = *aPosAccum + padding / 2 + field_height / 2;
708 
709  *aPosAccum += padding + field_height;
710 
711  return placement;
712  }
#define WIRE_V_SPACING
T round_n(const T &value, const T &n, bool aRoundUp)
Round up/down to the nearest multiple of n.
#define FIELD_PADDING
int GetHeight() const
Definition: eda_rect.h:110
const EDA_RECT GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_field.cpp:305

References FIELD_PADDING, SCH_FIELD::GetBoundingBox(), EDA_RECT::GetHeight(), m_align_to_grid, round_n(), and WIRE_V_SPACING.

Referenced by DoAutoplace().

◆ filterCollisions()

std::vector<SCH_ITEM*> AUTOPLACER::filterCollisions ( const EDA_RECT aRect)
inlineprotected

Filter a list of possible colliders to include only those that actually collide with a given rectangle.

Returns the new vector.

Definition at line 309 of file autoplace_fields.cpp.

310  {
311  std::vector<SCH_ITEM*> filtered;
312 
313  for( SCH_ITEM* item : m_colliders )
314  {
315  EDA_RECT item_box;
316 
317  if( SCH_SYMBOL* item_comp = dynamic_cast<SCH_SYMBOL*>( item ) )
318  item_box = item_comp->GetBodyAndPinsBoundingBox();
319  else
320  item_box = item->GetBoundingBox();
321 
322  if( item_box.Intersects( aRect ) )
323  filtered.push_back( item );
324  }
325  return filtered;
326  }
std::vector< SCH_ITEM * > m_colliders
Schematic symbol object.
Definition: sch_symbol.h:78
Handle the component boundary box.
Definition: eda_rect.h:42
bool Intersects(const EDA_RECT &aRect) const
Test for a common area between rectangles.
Definition: eda_rect.cpp:150
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182

References EDA_RECT::Intersects(), and m_colliders.

Referenced by fitFieldsBetweenWires(), and getCollidingSides().

◆ fitFieldsBetweenWires()

bool AUTOPLACER::fitFieldsBetweenWires ( EDA_RECT aBox,
SIDE  aSide 
)
inlineprotected

Shift a field box up or down a bit to make the fields fit between some wires.

Returns true if a shift was made.

Definition at line 592 of file autoplace_fields.cpp.

593  {
594  if( aSide != SIDE_TOP && aSide != SIDE_BOTTOM )
595  return false;
596 
597  std::vector<SCH_ITEM*> colliders = filterCollisions( *aBox );
598 
599  if( colliders.empty() )
600  return false;
601 
602  // Find the offset of the wires for proper positioning
603  int offset = 0;
604 
605  for( SCH_ITEM* item : colliders )
606  {
607  SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
608 
609  if( !line )
610  return false;
611 
612  wxPoint start = line->GetStartPoint(), end = line->GetEndPoint();
613 
614  if( start.y != end.y )
615  return false;
616 
617  int this_offset = (3 * WIRE_V_SPACING / 2) - ( start.y % WIRE_V_SPACING );
618 
619  if( offset == 0 )
620  offset = this_offset;
621  else if( offset != this_offset )
622  return false;
623  }
624 
625  // At this point we are recomputing the field box size. Do not
626  // return false after this point.
627  m_fbox_size = computeFBoxSize( /* aDynamic */ false );
628 
629  wxPoint pos = aBox->GetPosition();
630 
631  pos.y = round_n( pos.y, WIRE_V_SPACING, aSide == SIDE_BOTTOM );
632 
633  aBox->SetOrigin( pos );
634  return true;
635  }
wxPoint GetStartPoint() const
Definition: sch_line.h:90
void SetOrigin(const wxPoint &pos)
Definition: eda_rect.h:121
#define WIRE_V_SPACING
T round_n(const T &value, const T &n, bool aRoundUp)
Round up/down to the nearest multiple of n.
std::vector< SCH_ITEM * > filterCollisions(const EDA_RECT &aRect)
Filter a list of possible colliders to include only those that actually collide with a given rectangl...
const wxPoint GetPosition() const
Definition: eda_rect.h:102
wxSize computeFBoxSize(bool aDynamic)
Compute and return the size of the fields' bounding box.
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
static const SIDE SIDE_BOTTOM
static const SIDE SIDE_TOP
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
wxPoint GetEndPoint() const
Definition: sch_line.h:93

References computeFBoxSize(), filterCollisions(), SCH_LINE::GetEndPoint(), EDA_RECT::GetPosition(), SCH_LINE::GetStartPoint(), m_fbox_size, round_n(), EDA_RECT::SetOrigin(), SIDE_BOTTOM, SIDE_TOP, and WIRE_V_SPACING.

Referenced by DoAutoplace().

◆ getCollidingSides()

std::vector<SIDE_AND_COLL> AUTOPLACER::getCollidingSides ( )
inlineprotected

Return a list of the sides where a field set would collide with another item.

Definition at line 399 of file autoplace_fields.cpp.

400  {
401  SIDE sides_init[] = { SIDE_RIGHT, SIDE_TOP, SIDE_LEFT, SIDE_BOTTOM };
402  std::vector<SIDE> sides( sides_init, sides_init + arrayDim( sides_init ) );
403  std::vector<SIDE_AND_COLL> colliding;
404 
405  // Iterate over all sides and find the ones that collide
406  for( SIDE side : sides )
407  {
408  SIDE_AND_NPINS sideandpins;
409  sideandpins.side = side;
410  sideandpins.pins = pinsOnSide( side );
411 
412  EDA_RECT box( fieldBoxPlacement( sideandpins ), m_fbox_size );
413 
414  COLLISION collision = COLLIDE_NONE;
415 
416  for( SCH_ITEM* collider : filterCollisions( box ) )
417  {
418  SCH_LINE* line = dynamic_cast<SCH_LINE*>( collider );
419 
420  if( line && !side.x )
421  {
422  wxPoint start = line->GetStartPoint(), end = line->GetEndPoint();
423 
424  if( start.y == end.y && collision != COLLIDE_OBJECTS )
425  collision = COLLIDE_H_WIRES;
426  else
427  collision = COLLIDE_OBJECTS;
428  }
429  else
430  {
431  collision = COLLIDE_OBJECTS;
432  }
433  }
434 
435  if( collision != COLLIDE_NONE )
436  colliding.push_back( { side, collision } );
437  }
438 
439  return colliding;
440  }
wxPoint GetStartPoint() const
Definition: sch_line.h:90
std::vector< SCH_ITEM * > filterCollisions(const EDA_RECT &aRect)
Filter a list of possible colliders to include only those that actually collide with a given rectangl...
static const SIDE SIDE_LEFT
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
unsigned pinsOnSide(SIDE aSide)
Count the number of pins on a side of the symbol.
static const SIDE SIDE_RIGHT
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:37
static const SIDE SIDE_BOTTOM
wxPoint fieldBoxPlacement(SIDE_AND_NPINS aFieldSideAndPins)
Return the position of the field bounding box.
Handle the component boundary box.
Definition: eda_rect.h:42
static const SIDE SIDE_TOP
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182
wxPoint GetEndPoint() const
Definition: sch_line.h:93

References arrayDim(), COLLIDE_H_WIRES, COLLIDE_NONE, COLLIDE_OBJECTS, fieldBoxPlacement(), filterCollisions(), SCH_LINE::GetEndPoint(), SCH_LINE::GetStartPoint(), m_fbox_size, AUTOPLACER::SIDE_AND_NPINS::pins, pinsOnSide(), AUTOPLACER::SIDE_AND_NPINS::side, SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT, and SIDE_TOP.

Referenced by chooseSideForFields().

◆ getPinSide()

SIDE AUTOPLACER::getPinSide ( SCH_PIN aPin)
inlineprotected

Return the side that a pin is on.

Definition at line 235 of file autoplace_fields.cpp.

236  {
237  int pin_orient = aPin->GetLibPin()->PinDrawOrient( m_symbol->GetTransform() );
238 
239  switch( pin_orient )
240  {
241  case PIN_RIGHT: return SIDE_LEFT;
242  case PIN_LEFT: return SIDE_RIGHT;
243  case PIN_UP: return SIDE_BOTTOM;
244  case PIN_DOWN: return SIDE_TOP;
245  default:
246  wxFAIL_MSG( "Invalid pin orientation" );
247  return SIDE_LEFT;
248  }
249  }
LIB_PIN * GetLibPin() const
Definition: sch_pin.h:59
Definition: lib_pin.h:48
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:831
TRANSFORM & GetTransform()
Definition: sch_symbol.h:231
static const SIDE SIDE_LEFT
SCH_SYMBOL * m_symbol
static const SIDE SIDE_RIGHT
static const SIDE SIDE_BOTTOM
static const SIDE SIDE_TOP

References SCH_PIN::GetLibPin(), SCH_SYMBOL::GetTransform(), m_symbol, PIN_DOWN, PIN_LEFT, PIN_RIGHT, PIN_UP, LIB_PIN::PinDrawOrient(), SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT, and SIDE_TOP.

Referenced by fieldBoxPlacement(), and pinsOnSide().

◆ getPossibleCollisions()

void AUTOPLACER::getPossibleCollisions ( std::vector< SCH_ITEM * > &  aItems)
inlineprotected

Populate a list of all drawing items that may collide with the fields.

That is, all drawing items, including other fields, that are not the current symbol or its own fields.

Definition at line 274 of file autoplace_fields.cpp.

275  {
276  wxCHECK_RET( m_screen, "getPossibleCollisions() with null m_screen" );
277 
279  std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
280 
281  for( SIDE_AND_NPINS& side : sides )
282  {
283  EDA_RECT box( fieldBoxPlacement( side ), m_fbox_size );
284  box.Merge( symbolBox );
285 
286  for( SCH_ITEM* item : m_screen->Items().Overlapping( box ) )
287  {
288  if( SCH_SYMBOL* candidate = dynamic_cast<SCH_SYMBOL*>( item ) )
289  {
290  if( candidate == m_symbol )
291  continue;
292 
293  std::vector<SCH_FIELD*> fields;
294  candidate->GetFields( fields, /* aVisibleOnly */ true );
295 
296  for( SCH_FIELD* field : fields )
297  aItems.push_back( field );
298  }
299 
300  aItems.push_back( item );
301  }
302  }
303  }
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:49
std::vector< SIDE_AND_NPINS > getPreferredSides()
Return a list with the preferred field sides for the symbol, in decreasing order of preference.
EDA_RECT GetBodyAndPinsBoundingBox() const
Return a bounding box for the symbol body and pins but not the fields.
SCH_SCREEN * m_screen
SCH_SYMBOL * m_symbol
EE_TYPE Overlapping(const EDA_RECT &aRect) const
Definition: sch_rtree.h:235
Schematic symbol object.
Definition: sch_symbol.h:78
wxPoint fieldBoxPlacement(SIDE_AND_NPINS aFieldSideAndPins)
Return the position of the field bounding box.
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:110
Handle the component boundary box.
Definition: eda_rect.h:42
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:182

References fieldBoxPlacement(), SCH_SYMBOL::GetBodyAndPinsBoundingBox(), getPreferredSides(), SCH_SCREEN::Items(), m_fbox_size, m_screen, m_symbol, EDA_RECT::Merge(), and EE_RTREE::Overlapping().

Referenced by AUTOPLACER().

◆ getPreferredSides()

std::vector<SIDE_AND_NPINS> AUTOPLACER::getPreferredSides ( )
inlineprotected

Return a list with the preferred field sides for the symbol, in decreasing order of preference.

Definition at line 332 of file autoplace_fields.cpp.

333  {
334  SIDE_AND_NPINS sides_init[] = {
336  { SIDE_TOP, pinsOnSide( SIDE_TOP ) },
339  };
340  std::vector<SIDE_AND_NPINS> sides( sides_init, sides_init + arrayDim( sides_init ) );
341 
342  int orient = m_symbol->GetOrientation();
343  int orient_angle = orient & 0xff; // enum is a bitmask
344  bool h_mirrored = ( ( orient & SYM_MIRROR_X )
345  && ( orient_angle == SYM_ORIENT_0 || orient_angle == SYM_ORIENT_180 ) );
346  double w = double( m_symbol_bbox.GetWidth() );
347  double h = double( m_symbol_bbox.GetHeight() );
348 
349  // The preferred-sides heuristics are a bit magical. These were determined mostly
350  // by trial and error.
351 
352  if( m_is_power_symbol )
353  {
354  // For power symbols, we generally want the label at the top first.
355  switch( orient_angle )
356  {
357  case SYM_ORIENT_0:
358  std::swap( sides[0], sides[1] );
359  std::swap( sides[1], sides[3] );
360  // TOP, BOTTOM, RIGHT, LEFT
361  break;
362  case SYM_ORIENT_90:
363  std::swap( sides[0], sides[2] );
364  std::swap( sides[1], sides[2] );
365  // LEFT, RIGHT, TOP, BOTTOM
366  break;
367  case SYM_ORIENT_180:
368  std::swap( sides[0], sides[3] );
369  // BOTTOM, TOP, LEFT, RIGHT
370  break;
371  case SYM_ORIENT_270:
372  std::swap( sides[1], sides[2] );
373  // RIGHT, LEFT, TOP, BOTTOM
374  break;
375  }
376  }
377  else
378  {
379  // If the symbol is horizontally mirrored, swap left and right
380  if( h_mirrored )
381  {
382  std::swap( sides[0], sides[2] );
383  }
384 
385  // If the symbol is very long or is a power symbol, swap H and V
386  if( w/h > 3.0 )
387  {
388  std::swap( sides[0], sides[1] );
389  std::swap( sides[1], sides[3] );
390  }
391  }
392 
393  return sides;
394  }
int GetWidth() const
Definition: eda_rect.h:109
EDA_RECT m_symbol_bbox
static const SIDE SIDE_LEFT
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
unsigned pinsOnSide(SIDE aSide)
Count the number of pins on a side of the symbol.
SCH_SYMBOL * m_symbol
int GetHeight() const
Definition: eda_rect.h:110
static const SIDE SIDE_RIGHT
static const SIDE SIDE_BOTTOM
int GetOrientation()
Get the display symbol orientation.
static const SIDE SIDE_TOP

References arrayDim(), EDA_RECT::GetHeight(), SCH_SYMBOL::GetOrientation(), EDA_RECT::GetWidth(), m_is_power_symbol, m_symbol, m_symbol_bbox, pinsOnSide(), SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT, SIDE_TOP, SYM_MIRROR_X, SYM_ORIENT_0, SYM_ORIENT_180, SYM_ORIENT_270, and SYM_ORIENT_90.

Referenced by chooseSideForFields(), and getPossibleCollisions().

◆ justifyField()

void AUTOPLACER::justifyField ( SCH_FIELD aField,
SIDE  aFieldSide 
)
inlineprotected

Set the justification of a field based on the side it's supposed to be on, taking into account whether the field will be displayed with flipped justification due to mirroring.

Definition at line 525 of file autoplace_fields.cpp.

526  {
527  // Justification is set twice to allow IsHorizJustifyFlipped() to work correctly.
528  aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x ) );
529  aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x
530  * ( aField->IsHorizJustifyFlipped() ? -1 : 1 ) ) );
532  }
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:223
EDA_TEXT_HJUSTIFY_T TO_HJUSTIFY(int x)
Convert an integer to a horizontal justification; neg=L zero=C pos=R.
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:222
bool IsHorizJustifyFlipped() const
Return whether the field will be rendered with the horizontal justification inverted due to rotation ...
Definition: sch_field.cpp:347

References GR_TEXT_VJUSTIFY_CENTER, SCH_FIELD::IsHorizJustifyFlipped(), EDA_TEXT::SetHorizJustify(), EDA_TEXT::SetVertJustify(), and TO_HJUSTIFY().

Referenced by DoAutoplace().

◆ pinsOnSide()

unsigned AUTOPLACER::pinsOnSide ( SIDE  aSide)
inlineprotected

Count the number of pins on a side of the symbol.

Definition at line 254 of file autoplace_fields.cpp.

255  {
256  unsigned pin_count = 0;
257 
258  for( SCH_PIN* each_pin : m_symbol->GetPins() )
259  {
260  if( !each_pin->IsVisible() && !m_is_power_symbol )
261  continue;
262 
263  if( getPinSide( each_pin ) == aSide )
264  ++pin_count;
265  }
266 
267  return pin_count;
268  }
SIDE getPinSide(SCH_PIN *aPin)
Return the side that a pin is on.
SCH_SYMBOL * m_symbol
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
Definition: sch_symbol.cpp:866

References SCH_SYMBOL::GetPins(), getPinSide(), m_is_power_symbol, and m_symbol.

Referenced by getCollidingSides(), and getPreferredSides().

Member Data Documentation

◆ m_align_to_grid

bool AUTOPLACER::m_align_to_grid
private

Definition at line 722 of file autoplace_fields.cpp.

Referenced by AUTOPLACER(), computeFBoxSize(), DoAutoplace(), and fieldVertPlacement().

◆ m_allow_rejustify

bool AUTOPLACER::m_allow_rejustify
private

Definition at line 721 of file autoplace_fields.cpp.

Referenced by AUTOPLACER(), and DoAutoplace().

◆ m_colliders

std::vector<SCH_ITEM*> AUTOPLACER::m_colliders
private

Definition at line 718 of file autoplace_fields.cpp.

Referenced by AUTOPLACER(), and filterCollisions().

◆ m_fbox_size

wxSize AUTOPLACER::m_fbox_size
private

◆ m_fields

std::vector<SCH_FIELD*> AUTOPLACER::m_fields
private

Definition at line 717 of file autoplace_fields.cpp.

Referenced by AUTOPLACER(), computeFBoxSize(), and DoAutoplace().

◆ m_is_power_symbol

bool AUTOPLACER::m_is_power_symbol
private

Definition at line 723 of file autoplace_fields.cpp.

Referenced by AUTOPLACER(), fieldBoxPlacement(), getPreferredSides(), and pinsOnSide().

◆ m_screen

SCH_SCREEN* AUTOPLACER::m_screen
private

Definition at line 715 of file autoplace_fields.cpp.

Referenced by getPossibleCollisions().

◆ m_symbol

◆ m_symbol_bbox

EDA_RECT AUTOPLACER::m_symbol_bbox
private

Definition at line 719 of file autoplace_fields.cpp.

Referenced by AUTOPLACER(), fieldBoxPlacement(), and getPreferredSides().

◆ SIDE_BOTTOM

const AUTOPLACER::SIDE AUTOPLACER::SIDE_BOTTOM
static

◆ SIDE_LEFT

const AUTOPLACER::SIDE AUTOPLACER::SIDE_LEFT
static

◆ SIDE_RIGHT

const AUTOPLACER::SIDE AUTOPLACER::SIDE_RIGHT
static

◆ SIDE_TOP

const AUTOPLACER::SIDE AUTOPLACER::SIDE_TOP
static

The documentation for this class was generated from the following file: