KiCad PCB EDA Suite
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 KiCad Developers, see change_log.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 <schframe.h>
56 #include <hotkeys_basic.h>
57 #include <sch_component.h>
58 #include <sch_line.h>
59 #include <lib_pin.h>
60 #include <class_drawpanel.h>
61 #include <class_libentry.h>
62 #include <eeschema_config.h>
63 #include <kiface_i.h>
64 #include <vector>
65 #include <algorithm>
66 
67 #define FIELD_PADDING 10 // arbitrarily chosen for aesthetics
68 #define FIELD_PADDING_ALIGNED 18 // aligns 50 mil text to a 100 mil grid
69 #define WIRE_V_SPACING 100
70 #define HPADDING 25
71 #define VPADDING 25
72 
77 template<typename T> T round_n( const T& value, const T& n, bool aRoundUp )
78 {
79  if( value % n )
80  return n * (value / n + (aRoundUp ? 1 : 0));
81  else
82  return value;
83 }
84 
85 
91 {
92  return static_cast<EDA_TEXT_HJUSTIFY_T>( x );
93 }
94 
95 
97 {
100  std::vector<SCH_FIELD*> m_fields;
101  std::vector<SCH_ITEM*> m_colliders;
103  wxSize m_fbox_size;
106 
107 public:
108  typedef wxPoint SIDE;
109  static const SIDE SIDE_TOP, SIDE_BOTTOM, SIDE_LEFT, SIDE_RIGHT;
111 
113  {
114  SIDE side;
115  unsigned pins;
116  };
117 
119  {
120  SIDE side;
122  };
123 
124 
125  AUTOPLACER( SCH_COMPONENT* aComponent, SCH_SCREEN* aScreen )
126  :m_screen( aScreen ), m_component( aComponent )
127  {
128  m_component->GetFields( m_fields, /* aVisibleOnly */ true );
129  Kiface().KifaceSettings()->Read( AutoplaceJustifyEntry, &m_allow_rejustify, true );
130  Kiface().KifaceSettings()->Read( AutoplaceAlignEntry, &m_align_to_grid, false );
131 
132  m_comp_bbox = m_component->GetBodyBoundingBox();
133  m_fbox_size = ComputeFBoxSize( /* aDynamic */ true );
134 
135  m_power_symbol = ! m_component->IsInNetlist();
136 
137  if( aScreen )
138  get_possible_colliders( m_colliders );
139  }
140 
141 
147  void DoAutoplace( bool aManual )
148  {
149  bool force_wire_spacing = false;
150  SIDE field_side = choose_side_for_fields( aManual );
151  wxPoint fbox_pos = field_box_placement( field_side );
152  EDA_RECT field_box( fbox_pos, m_fbox_size );
153 
154  if( aManual )
155  force_wire_spacing = fit_fields_between_wires( &field_box, field_side );
156 
157  // Move the fields
158  int last_y_coord = field_box.GetTop();
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  justify_field( field, field_side );
165 
166  wxPoint pos(
167  field_horiz_placement( field, field_box ),
168  field_vert_placement( field, field_box, &last_y_coord, !force_wire_spacing ) );
169 
170  if( m_align_to_grid )
171  {
172  pos.x = round_n( pos.x, 50, field_side.x >= 0 );
173  pos.y = round_n( pos.y, 50, field_side.y == 1 );
174  }
175 
176  field->SetPosition( pos );
177  }
178  }
179 
180 
181 protected:
186  wxSize ComputeFBoxSize( bool aDynamic )
187  {
188  int max_field_width = 0;
189  int total_height = 0;
190 
191  for( SCH_FIELD* field : m_fields )
192  {
193  int field_width;
194  int field_height;
195 
196  if( m_component->GetTransform().y1 )
197  {
198  field->SetTextAngle( TEXT_ANGLE_VERT );
199  }
200  else
201  {
202  field->SetTextAngle( TEXT_ANGLE_HORIZ );
203  }
204 
205  field_width = field->GetBoundingBox().GetWidth();
206  field_height = field->GetBoundingBox().GetHeight();
207 
208  max_field_width = std::max( max_field_width, field_width );
209 
210  if( aDynamic )
211  total_height += field_height + get_field_padding();
212  else
213  total_height += WIRE_V_SPACING;
214 
215  }
216 
217  return wxSize( max_field_width, total_height );
218  }
219 
220 
225  SIDE get_pin_side( LIB_PIN* aPin )
226  {
227  int pin_orient = aPin->PinDrawOrient( m_component->GetTransform() );
228  switch( pin_orient )
229  {
230  case PIN_RIGHT: return SIDE_LEFT;
231  case PIN_LEFT: return SIDE_RIGHT;
232  case PIN_UP: return SIDE_BOTTOM;
233  case PIN_DOWN: return SIDE_TOP;
234  default:
235  wxFAIL_MSG( "Invalid pin orientation" );
236  return SIDE_LEFT;
237  }
238  }
239 
240 
245  unsigned pins_on_side( SIDE aSide )
246  {
247  unsigned pin_count = 0;
248 
249  std::vector<LIB_PIN*> pins;
250  m_component->GetPins( pins );
251 
252  for( LIB_PIN* each_pin : pins )
253  {
254  if( !each_pin->IsVisible() && !m_power_symbol )
255  continue;
256  if( get_pin_side( each_pin ) == aSide )
257  ++pin_count;
258  }
259 
260  return pin_count;
261  }
262 
263 
270  void get_possible_colliders( std::vector<SCH_ITEM*>& aItems )
271  {
272  wxASSERT_MSG( m_screen, "get_possible_colliders() with null m_screen" );
273  for( SCH_ITEM* item = m_screen->GetDrawItems(); item; item = item->Next() )
274  {
275  if( SCH_COMPONENT* comp = dynamic_cast<SCH_COMPONENT*>( item ) )
276  {
277  if( comp == m_component ) continue;
278 
279  std::vector<SCH_FIELD*> fields;
280  comp->GetFields( fields, /* aVisibleOnly */ true );
281  for( SCH_FIELD* field : fields )
282  aItems.push_back( field );
283  }
284  aItems.push_back( item );
285  }
286  }
287 
288 
294  std::vector<SCH_ITEM*> filtered_colliders( const EDA_RECT& aRect )
295  {
296  std::vector<SCH_ITEM*> filtered;
297  for( SCH_ITEM* item : m_colliders )
298  {
299  EDA_RECT item_box;
300  if( SCH_COMPONENT* item_comp = dynamic_cast<SCH_COMPONENT*>( item ) )
301  item_box = item_comp->GetBodyBoundingBox();
302  else
303  item_box = item->GetBoundingBox();
304 
305  if( item_box.Intersects( aRect ) )
306  filtered.push_back( item );
307  }
308  return filtered;
309  }
310 
311 
317  std::vector<SIDE_AND_NPINS> get_preferred_sides()
318  {
319  SIDE_AND_NPINS sides_init[] = {
320  { SIDE_RIGHT, pins_on_side( SIDE_RIGHT ) },
321  { SIDE_TOP, pins_on_side( SIDE_TOP ) },
322  { SIDE_LEFT, pins_on_side( SIDE_LEFT ) },
323  { SIDE_BOTTOM, pins_on_side( SIDE_BOTTOM ) },
324  };
325  std::vector<SIDE_AND_NPINS> sides( sides_init, sides_init + DIM( sides_init ) );
326 
327  int orient = m_component->GetOrientation();
328  int orient_angle = orient & 0xff; // enum is a bitmask
329  bool h_mirrored = ( ( orient & CMP_MIRROR_X )
330  && ( orient_angle == CMP_ORIENT_0 || orient_angle == CMP_ORIENT_180 ) );
331  double w = double( m_comp_bbox.GetWidth() );
332  double h = double( m_comp_bbox.GetHeight() );
333 
334  // The preferred-sides heuristics are a bit magical. These were determined mostly
335  // by trial and error.
336 
337  if( m_power_symbol )
338  {
339  // For power symbols, we generally want the label at the top first.
340  switch( orient_angle )
341  {
342  case CMP_ORIENT_0:
343  std::swap( sides[0], sides[1] );
344  std::swap( sides[1], sides[3] );
345  // TOP, BOTTOM, RIGHT, LEFT
346  break;
347  case CMP_ORIENT_90:
348  std::swap( sides[0], sides[2] );
349  std::swap( sides[1], sides[2] );
350  // LEFT, RIGHT, TOP, BOTTOM
351  break;
352  case CMP_ORIENT_180:
353  std::swap( sides[0], sides[3] );
354  // BOTTOM, TOP, LEFT, RIGHT
355  break;
356  case CMP_ORIENT_270:
357  std::swap( sides[1], sides[2] );
358  // RIGHT, LEFT, TOP, BOTTOM
359  break;
360  }
361  }
362  else
363  {
364  // If the component is horizontally mirrored, swap left and right
365  if( h_mirrored )
366  {
367  std::swap( sides[0], sides[2] );
368  }
369 
370  // If the component is very long or is a power symbol, swap H and V
371  if( w/h > 3.0 )
372  {
373  std::swap( sides[0], sides[1] );
374  std::swap( sides[1], sides[3] );
375  }
376  }
377 
378  return sides;
379  }
380 
381 
386  std::vector<SIDE_AND_COLL> get_colliding_sides()
387  {
388  SIDE sides_init[] = { SIDE_RIGHT, SIDE_TOP, SIDE_LEFT, SIDE_BOTTOM };
389  std::vector<SIDE> sides( sides_init, sides_init + DIM( sides_init ) );
390  std::vector<SIDE_AND_COLL> colliding;
391 
392  // Iterate over all sides and find the ones that collide
393  for( SIDE side : sides )
394  {
395  EDA_RECT box( field_box_placement( side ), m_fbox_size );
396 
397  COLLISION collision = COLLIDE_NONE;
398  for( SCH_ITEM* collider : filtered_colliders( box ) )
399  {
400  SCH_LINE* line = dynamic_cast<SCH_LINE*>( collider );
401  if( line && !side.x )
402  {
403  wxPoint start = line->GetStartPoint(), end = line->GetEndPoint();
404  if( start.y == end.y && collision != COLLIDE_OBJECTS )
405  collision = COLLIDE_H_WIRES;
406  else
407  collision = COLLIDE_OBJECTS;
408  }
409  else
410  collision = COLLIDE_OBJECTS;
411  }
412 
413  if( collision != COLLIDE_NONE )
414  colliding.push_back( { side, collision } );
415  }
416 
417  return colliding;
418  }
419 
420 
426  SIDE_AND_NPINS choose_side_filtered( std::vector<SIDE_AND_NPINS>& aSides,
427  const std::vector<SIDE_AND_COLL>& aCollidingSides, COLLISION aCollision,
428  SIDE_AND_NPINS aLastSelection)
429  {
430  SIDE_AND_NPINS sel = aLastSelection;
431 
432  std::vector<SIDE_AND_NPINS>::iterator it = aSides.begin();
433  while( it != aSides.end() )
434  {
435  bool collide = false;
436  for( SIDE_AND_COLL collision : aCollidingSides )
437  {
438  if( collision.side == it->side && collision.collision == aCollision )
439  collide = true;
440  }
441  if( !collide )
442  ++it;
443  else
444  {
445  if( it->pins <= sel.pins )
446  {
447  sel.pins = it->pins;
448  sel.side = it->side;
449  }
450  it = aSides.erase( it );
451  }
452  }
453  return sel;
454  }
455 
456 
463  SIDE choose_side_for_fields( bool aAvoidCollisions )
464  {
465  std::vector<SIDE_AND_NPINS> sides = get_preferred_sides();
466 
467  std::reverse( sides.begin(), sides.end() );
468  SIDE_AND_NPINS side = { wxPoint( 1, 0 ), UINT_MAX };
469 
470  if( aAvoidCollisions )
471  {
472  std::vector<SIDE_AND_COLL> colliding_sides = get_colliding_sides();
473  side = choose_side_filtered( sides, colliding_sides, COLLIDE_OBJECTS, side );
474  side = choose_side_filtered( sides, colliding_sides, COLLIDE_H_WIRES, side );
475  }
476 
477  for( SIDE_AND_NPINS& each_side : sides | boost::adaptors::reversed )
478  {
479  if( !each_side.pins ) return each_side.side;
480  }
481 
482  for( SIDE_AND_NPINS& each_side : sides )
483  {
484  if( each_side.pins <= side.pins )
485  {
486  side.pins = each_side.pins;
487  side.side = each_side.side;
488  }
489  }
490 
491  return side.side;
492  }
493 
494 
501  void justify_field( SCH_FIELD* aField, SIDE aFieldSide )
502  {
503  // Justification is set twice to allow IsHorizJustifyFlipped() to work correctly.
504  aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x ) );
505  aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x *
506  ( aField->IsHorizJustifyFlipped() ? -1 : 1 ) ) );
508  }
509 
510 
515  wxPoint field_box_placement( SIDE aFieldSide )
516  {
517  wxPoint fbox_center = m_comp_bbox.Centre();
518  int offs_x = ( m_comp_bbox.GetWidth() + m_fbox_size.GetWidth() ) / 2 + HPADDING;
519  int offs_y = ( m_comp_bbox.GetHeight() + m_fbox_size.GetHeight() ) / 2 + VPADDING;
520 
521  fbox_center.x += aFieldSide.x * offs_x;
522  fbox_center.y += aFieldSide.y * offs_y;
523 
524  wxPoint fbox_pos(
525  fbox_center.x - m_fbox_size.GetWidth() / 2,
526  fbox_center.y - m_fbox_size.GetHeight() / 2 );
527 
528  return fbox_pos;
529  }
530 
531 
537  bool fit_fields_between_wires( EDA_RECT* aBox, SIDE aSide )
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  {
574  pos.y = m_comp_bbox.GetBottom() - get_field_padding();
575  }
576  else
577  {
578  pos.y = m_comp_bbox.GetTop() - m_fbox_size.y + get_field_padding();
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 
598  int field_horiz_placement( SCH_FIELD *aField, const EDA_RECT &aFieldBox )
599  {
600  int field_hjust;
601  int field_xcoord;
602 
603  if( aField->IsHorizJustifyFlipped() )
604  field_hjust = -aField->GetHorizJustify();
605  else
606  field_hjust = aField->GetHorizJustify();
607 
608  switch( field_hjust )
609  {
611  field_xcoord = aFieldBox.GetLeft();
612  break;
614  field_xcoord = aFieldBox.Centre().x;
615  break;
617  field_xcoord = aFieldBox.GetRight();
618  break;
619  default:
620  wxFAIL_MSG( "Unexpected value for SCH_FIELD::GetHorizJustify()" );
621  field_xcoord = aFieldBox.Centre().x; // Most are centered
622  }
623 
624  return field_xcoord;
625  }
626 
639  int field_vert_placement( SCH_FIELD *aField, const EDA_RECT &aFieldBox, int *aPosAccum,
640  bool aDynamic )
641  {
642  int field_height;
643  int padding;
644 
645  if( aDynamic )
646  {
647  field_height = aField->GetBoundingBox().GetHeight();
648 
649  padding = get_field_padding();
650  }
651  else
652  {
653  field_height = WIRE_V_SPACING / 2;
654  padding = WIRE_V_SPACING / 2;
655  }
656 
657  int placement = *aPosAccum + padding / 2 + field_height / 2;
658 
659  *aPosAccum += padding + field_height;
660 
661  return placement;
662  }
663 
669  {
670  if( m_align_to_grid )
671  return FIELD_PADDING_ALIGNED;
672  else
673  return FIELD_PADDING;
674  }
675 
676 };
677 
682 
683 
684 void SCH_EDIT_FRAME::OnAutoplaceFields( wxCommandEvent& aEvent )
685 {
686  SCH_SCREEN* screen = GetScreen();
687  SCH_ITEM* item = screen->GetCurItem();
688 
689  // Get the item under cursor if we're not currently moving something
690  if( !item )
691  {
692  if( aEvent.GetInt() == 0 )
693  return;
694 
695  EDA_HOTKEY_CLIENT_DATA& data = dynamic_cast<EDA_HOTKEY_CLIENT_DATA&>(
696  *aEvent.GetClientObject() );
697  item = LocateItem( data.GetPosition(), SCH_COLLECTOR::MovableItems, aEvent.GetInt() );
698  screen->SetCurItem( NULL );
699  if( !item || item->GetFlags() )
700  return;
701  }
702 
703  SCH_COMPONENT* component = dynamic_cast<SCH_COMPONENT*>( item );
704  if( !component )
705  return;
706 
707  if( !component->IsNew() )
708  SaveCopyInUndoList( component, UR_CHANGED );
709 
710  component->AutoplaceFields( screen, /* aManual */ true );
711 
712  GetCanvas()->Refresh();
713  OnModify();
714 }
715 
716 
717 void SCH_COMPONENT::AutoplaceFields( SCH_SCREEN* aScreen, bool aManual )
718 {
719  if( aManual )
720  wxASSERT_MSG( aScreen, "A SCH_SCREEN pointer must be given for manual autoplacement" );
721  AUTOPLACER autoplacer( this, aScreen );
722  autoplacer.DoAutoplace( aManual );
724 }
void justify_field(SCH_FIELD *aField, SIDE aFieldSide)
Function justify_field Set the justification of a field based on the side it's supposed to be on...
#define DIM(x)
of elements in an array
Definition: macros.h:98
#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:91
Class SCH_FIELD instances are attached to a component and provide a place for the component's value...
Definition: sch_field.h:56
wxSize ComputeFBoxSize(bool aDynamic)
Compute and return the size of the fields' bounding box.
STATUS_FLAGS GetFlags() const
Definition: base_struct.h:255
unsigned pins_on_side(SIDE aSide)
Function pins_on_side 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:47
#define VPADDING
TRANSFORM & GetTransform() const
int GetLeft() const
std::vector< SIDE_AND_COLL > get_colliding_sides()
Function get_colliding_sides Return a list of the sides where a field set would collide with another ...
int GetOrientation()
Function GetOrientation Used to display component orientation (in dialog editor or info) ...
void SaveCopyInUndoList(SCH_ITEM *aItemToCopy, UNDO_REDO_T aTypeCommand, const wxPoint &aTransformPoint=wxPoint(0, 0))
Function SaveCopyInUndoList.
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Definition: draw_panel.cpp:326
bool IsNew() const
Definition: base_struct.h:216
bool collide(T aObject, U aAnotherObject, int aMinDistance)
collide template method
Definition: shape_index.h:91
EDA_DRAW_PANEL * GetCanvas()
Definition: draw_frame.h:299
void OnModify()
Function OnModify Must be called after a schematic change in order to set the "modify" flag of the cu...
Definition: schframe.cpp:761
T
enum T contains all this lexer's tokens.
#define HPADDING
SCH_COMPONENT * m_component
int GetHeight() const
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)
Function choose_side_filtered Choose a side for the fields, filtered on only one side collision type...
wxPoint field_box_placement(SIDE aFieldSide)
Function field_box_placement Returns the position of the field bounding box.
void SetOrigin(const wxPoint &pos)
wxPoint GetEndPoint() const
Definition: sch_line.h:75
Definition: lib_pin.h:54
EDA_RECT GetBodyBoundingBox() const
Function GetBodyBoundingBox Return a bounding box for the component body but not the fields...
static const KICAD_T MovableItems[]
A scan list for all movable schematic items.
EDA_TEXT_HJUSTIFY_T GetHorizJustify() const
Definition: eda_text.h:190
SCH_ITEM * Next() const
SCH_ITEM * LocateItem(const wxPoint &aPosition, const KICAD_T aFilterList[]=SCH_COLLECTOR::AllItems, int aHotKeyCommandId=0)
Function LocateItem checks for items at aPosition matching the types in aFilterList.
#define TEXT_ANGLE_VERT
Definition: common.h:92
#define WIRE_V_SPACING
T round_n(const T &value, const T &n, bool aRoundUp)
Function round_n Round up/down to the nearest multiple of n.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Definition: kicad.cpp:52
#define FIELD_PADDING_ALIGNED
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Function GetFields populates a std::vector with SCH_FIELDs.
bool fit_fields_between_wires(EDA_RECT *aBox, SIDE aSide)
Function fit_fields_between_wires Shift a field box up or down a bit to make the fields fit between s...
int field_horiz_placement(SCH_FIELD *aField, const EDA_RECT &aFieldBox)
Function field_horiz_placement Place a field horizontally, taking into account the field width and ju...
wxPoint GetStartPoint() const
Definition: sch_line.h:71
SCH_SCREEN * GetScreen() const override
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
Definition: schframe.cpp:520
int y1
Definition: transform.h:49
Class EDA_HOTKEY_CLIENT_DATA provides client data member for hotkeys to include in command events gen...
static const SIDE SIDE_LEFT
SCH_SCREEN * m_screen
const wxChar AutoplaceAlignEntry[]
std::vector< SCH_ITEM * > m_colliders
SCH_ITEM * GetCurItem() const
Function GetCurItem returns the currently selected SCH_ITEM, overriding BASE_SCREEN::GetCurItem().
Class LIB_ITEM definition.
int field_vert_placement(SCH_FIELD *aField, const EDA_RECT &aFieldBox, int *aPosAccum, bool aDynamic)
Function field_vert_placement Place a field vertically.
void SetVertJustify(EDA_TEXT_VJUSTIFY_T aType)
Definition: eda_text.h:194
wxConfigBase * KifaceSettings() const
Definition: kiface_i.h:101
void OnAutoplaceFields(wxCommandEvent &aEvent)
Function OnAutoplaceFields handles the ID_AUTOPLACE_FIELDS event.
int GetBottom() const
wxPoint Centre() const
bool IsInNetlist() const
#define FIELD_PADDING
int GetRight() const
EDA_RECT m_comp_bbox
EDA_TEXT_HJUSTIFY_T TO_HJUSTIFY(int x)
Function TO_HJUSTIFY Converts an integer to a horizontal justification; neg=L zero=C pos=R...
const wxPoint & GetPosition() const
static const SIDE SIDE_RIGHT
SIDE get_pin_side(LIB_PIN *aPin)
Function get_pin_side Return the side that a pin is on.
SCH_ITEM * GetDrawItems() const
Function GetDrawItems().
bool Intersects(const EDA_RECT &aRect) const
Function Intersects tests for a common area between rectangles.
Definition the SCH_COMPONENT class for Eeschema.
void GetPins(std::vector< LIB_PIN * > &aPinsList)
Function GetPins populate a vector with all the pins.
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual)
Function AutoplaceFields Automatically orient all the fields in the component.
Class SCH_LINE is a segment description base class to describe items which have 2 end points (track...
Definition: sch_line.h:42
const EDA_RECT GetBoundingBox() const override
Function GetBoundingBox returns the orthogonal, bounding box of this object for display purposes...
Definition: sch_field.cpp:251
#define max(a, b)
Definition: auxiliary.h:86
void SetHorizJustify(EDA_TEXT_HJUSTIFY_T aType)
Definition: eda_text.h:193
static const SIDE SIDE_BOTTOM
int get_field_padding()
Function get_field_padding Return the desired padding between fields.
void SetCurItem(SCH_ITEM *aItem)
Function SetCurItem sets the currently selected object, m_CurrentItem.
Class EDA_RECT handles the component boundary box.
Class SCH_COMPONENT describes a real schematic component.
Definition: sch_component.h:68
static void reverse(privcurve_t *curve)
Definition: trace.cpp:1020
int GetWidth() const
bool IsHorizJustifyFlipped() const
Function IsHorizJustifyFlipped Returns whether the field will be rendered with the horizontal justifi...
Definition: sch_field.cpp:297
SIDE choose_side_for_fields(bool aAvoidCollisions)
Function choose_side_for_fields Look where a component's pins are to pick a side to put the fields on...
void DoAutoplace(bool aManual)
Do the actual autoplacement.
Some functions to handle hotkeys in KiCad.
static const SIDE SIDE_TOP
std::vector< SIDE_AND_NPINS > get_preferred_sides()
Function get_preferred_sides Return a list with the preferred field sides for the component...
AUTOPLACER(SCH_COMPONENT *aComponent, SCH_SCREEN *aScreen)
AUTOPLACED m_fieldsAutoplaced
indicates status of field autoplacement
Definition: sch_component.h:96
void get_possible_colliders(std::vector< SCH_ITEM * > &aItems)
Function get_possible_colliders Populate a list of all drawing items that may collide with the fields...
void SetPosition(const wxPoint &aPosition) override
Function SetPosition set the schematic item position to aPosition.
Definition: sch_field.cpp:581
Class SCH_ITEM is a base class for any item which can be embedded within the SCHEMATIC container clas...
const wxChar AutoplaceJustifyEntry[]
int PinDrawOrient(const TRANSFORM &aTransform) const
Function PinDrawOrient returns the pin real orientation (PIN_UP, PIN_DOWN, PIN_RIGHT, PIN_LEFT), according to its orientation and the matrix transform (rot, mirror) aTransform.
Definition: lib_pin.cpp:1841
std::vector< SCH_ITEM * > filtered_colliders(const EDA_RECT &aRect)
Function filtered_colliders Filter a list of possible colliders to include only those that actually c...
int GetTop() const