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 <[email protected]>
5 * Copyright (C) 2015, 2020-2022 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 <hotkeys_basic.h>
57#include <sch_symbol.h>
58#include <sch_line.h>
59#include <lib_pin.h>
60#include <kiface_base.h>
61#include <vector>
62#include <algorithm>
63#include <tool/tool_manager.h>
65#include <eeschema_settings.h>
66#include <core/arraydim.h>
67
68#define FIELD_PADDING schIUScale.MilsToIU( 10 ) // arbitrarily chosen for aesthetics
69#define WIRE_V_SPACING schIUScale.MilsToIU( 100 )
70#define HPADDING schIUScale.MilsToIU( 25 )
71#define VPADDING schIUScale.MilsToIU( 25 )
72
76template<typename T> T round_n( const T& value, const T& n, bool aRoundUp )
77{
78 if( value % n )
79 return n * (value / n + (aRoundUp ? 1 : 0));
80 else
81 return value;
82}
83
84
86{
87public:
88 typedef VECTOR2I SIDE;
91
93 {
95 unsigned pins;
96 };
97
99 {
102 };
103
104 AUTOPLACER( SCH_SYMBOL* aSymbol, SCH_SCREEN* aScreen ) :
105 m_screen( aScreen ),
106 m_symbol( aSymbol )
107 {
108 m_symbol->GetFields( m_fields, /* aVisibleOnly */ true );
109
110 auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
111 wxASSERT( cfg );
112
113 m_allow_rejustify = false;
114 m_align_to_grid = true;
115
116 if( cfg )
117 {
118 m_allow_rejustify = cfg->m_AutoplaceFields.allow_rejustify;
119 m_align_to_grid = cfg->m_AutoplaceFields.align_to_grid;
120 }
121
123 m_fbox_size = computeFBoxSize( /* aDynamic */ true );
124
126
127 if( aScreen )
129 }
130
136 void DoAutoplace( bool aManual )
137 {
138 bool forceWireSpacing = false;
139 SIDE_AND_NPINS sideandpins = chooseSideForFields( aManual );
140 SIDE field_side = sideandpins.side;
141 VECTOR2I fbox_pos = fieldBoxPlacement( sideandpins );
142 BOX2I field_box( fbox_pos, m_fbox_size );
143
144 if( aManual )
145 forceWireSpacing = fitFieldsBetweenWires( &field_box, field_side );
146
147 // Move the fields
148 int last_y_coord = field_box.GetTop();
149
150 for( unsigned field_idx = 0; field_idx < m_fields.size(); ++field_idx )
151 {
152 SCH_FIELD* field = m_fields[field_idx];
153
154 if( !field->IsVisible() || !field->CanAutoplace() )
155 continue;
156
158 {
159 if( sideandpins.pins > 0 )
160 {
161 if( field_side == SIDE_TOP || field_side == SIDE_BOTTOM )
162 justifyField( field, SIDE_RIGHT );
163 else
164 justifyField( field, SIDE_TOP );
165 }
166 else
167 {
168 justifyField( field, field_side );
169 }
170 }
171
172 VECTOR2I pos( fieldHPlacement( field, field_box ),
173 fieldVPlacement( field, field_box, &last_y_coord, !forceWireSpacing ) );
174
175 if( m_align_to_grid )
176 {
177 if( abs( field_side.x ) > 0 )
178 pos.x = round_n( pos.x, schIUScale.MilsToIU( 50 ), field_side.x >= 0 );
179
180 if( abs( field_side.y ) > 0 )
181 pos.y = round_n( pos.y, schIUScale.MilsToIU( 50 ), field_side.y >= 0 );
182 }
183
184 field->SetPosition( pos );
185 }
186 }
187
188protected:
193 VECTOR2I computeFBoxSize( bool aDynamic )
194 {
195 int max_field_width = 0;
196 int total_height = 0;
197
198 std::vector<SCH_FIELD*> visibleFields;
199
200 for( SCH_FIELD* field : m_fields )
201 {
202 if( field->IsVisible() )
203 visibleFields.push_back( field );
204 }
205
206 for( SCH_FIELD* field : visibleFields )
207 {
208 if( field->CanAutoplace() )
209 {
210 if( m_symbol->GetTransform().y1 )
211 field->SetTextAngle( ANGLE_VERTICAL );
212 else
213 field->SetTextAngle( ANGLE_HORIZONTAL );
214 }
215
216 BOX2I bbox = field->GetBoundingBox();
217 int field_width = bbox.GetWidth();
218 int field_height = bbox.GetHeight();
219
220 max_field_width = std::max( max_field_width, field_width );
221
222 // Remove interline spacing from field_height for last line.
223 if( field == visibleFields.back() )
224 field_height *= 0.62;
225
226 if( !aDynamic )
227 total_height += WIRE_V_SPACING;
228 else if( m_align_to_grid )
229 total_height += round_n( field_height, schIUScale.MilsToIU( 50 ), true );
230 else
231 total_height += field_height + FIELD_PADDING;
232 }
233
234 return VECTOR2I( max_field_width, total_height );
235 }
236
241 {
242 int pin_orient = aPin->GetLibPin()->PinDrawOrient( m_symbol->GetTransform() );
243
244 switch( pin_orient )
245 {
246 case PIN_RIGHT: return SIDE_LEFT;
247 case PIN_LEFT: return SIDE_RIGHT;
248 case PIN_UP: return SIDE_BOTTOM;
249 case PIN_DOWN: return SIDE_TOP;
250 default:
251 wxFAIL_MSG( "Invalid pin orientation" );
252 return SIDE_LEFT;
253 }
254 }
255
259 unsigned pinsOnSide( SIDE aSide )
260 {
261 unsigned pin_count = 0;
262
263 for( SCH_PIN* each_pin : m_symbol->GetPins() )
264 {
265 if( !each_pin->IsVisible() && !m_is_power_symbol )
266 continue;
267
268 if( getPinSide( each_pin ) == aSide )
269 ++pin_count;
270 }
271
272 return pin_count;
273 }
274
279 void getPossibleCollisions( std::vector<SCH_ITEM*>& aItems )
280 {
281 wxCHECK_RET( m_screen, "getPossibleCollisions() with null m_screen" );
282
284 std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
285
286 for( SIDE_AND_NPINS& side : sides )
287 {
288 BOX2I box( fieldBoxPlacement( side ), m_fbox_size );
289 box.Merge( symbolBox );
290
291 for( SCH_ITEM* item : m_screen->Items().Overlapping( box ) )
292 {
293 if( SCH_SYMBOL* candidate = dynamic_cast<SCH_SYMBOL*>( item ) )
294 {
295 if( candidate == m_symbol )
296 continue;
297
298 std::vector<SCH_FIELD*> fields;
299 candidate->GetFields( fields, /* aVisibleOnly */ true );
300
301 for( SCH_FIELD* field : fields )
302 aItems.push_back( field );
303 }
304
305 aItems.push_back( item );
306 }
307 }
308 }
309
314 std::vector<SCH_ITEM*> filterCollisions( const BOX2I& aRect )
315 {
316 std::vector<SCH_ITEM*> filtered;
317
318 for( SCH_ITEM* item : m_colliders )
319 {
320 BOX2I item_box;
321
322 if( SCH_SYMBOL* item_comp = dynamic_cast<SCH_SYMBOL*>( item ) )
323 item_box = item_comp->GetBodyAndPinsBoundingBox();
324 else
325 item_box = item->GetBoundingBox();
326
327 if( item_box.Intersects( aRect ) )
328 filtered.push_back( item );
329 }
330
331 return filtered;
332 }
333
338 std::vector<SIDE_AND_NPINS> getPreferredSides()
339 {
340 SIDE_AND_NPINS sides_init[] = {
345 };
346 std::vector<SIDE_AND_NPINS> sides( sides_init, sides_init + arrayDim( sides_init ) );
347
348 int orient = m_symbol->GetOrientation();
349 int orient_angle = orient & 0xff; // enum is a bitmask
350 bool h_mirrored = ( ( orient & SYM_MIRROR_X )
351 && ( orient_angle == SYM_ORIENT_0 || orient_angle == SYM_ORIENT_180 ) );
352 double w = double( m_symbol_bbox.GetWidth() );
353 double h = double( m_symbol_bbox.GetHeight() );
354
355 // The preferred-sides heuristics are a bit magical. These were determined mostly
356 // by trial and error.
357
359 {
360 // For power symbols, we generally want the label at the top first.
361 switch( orient_angle )
362 {
363 case SYM_ORIENT_0:
364 std::swap( sides[0], sides[1] );
365 std::swap( sides[1], sides[3] );
366 // TOP, BOTTOM, RIGHT, LEFT
367 break;
368 case SYM_ORIENT_90:
369 std::swap( sides[0], sides[2] );
370 std::swap( sides[1], sides[2] );
371 // LEFT, RIGHT, TOP, BOTTOM
372 break;
373 case SYM_ORIENT_180:
374 std::swap( sides[0], sides[3] );
375 // BOTTOM, TOP, LEFT, RIGHT
376 break;
377 case SYM_ORIENT_270:
378 std::swap( sides[1], sides[2] );
379 // RIGHT, LEFT, TOP, BOTTOM
380 break;
381 }
382 }
383 else
384 {
385 // If the symbol is horizontally mirrored, swap left and right
386 if( h_mirrored )
387 {
388 std::swap( sides[0], sides[2] );
389 }
390
391 // If the symbol is very long or is a power symbol, swap H and V
392 if( w/h > 3.0 )
393 {
394 std::swap( sides[0], sides[1] );
395 std::swap( sides[1], sides[3] );
396 }
397 }
398
399 return sides;
400 }
401
405 std::vector<SIDE_AND_COLL> getCollidingSides()
406 {
407 SIDE sides_init[] = { SIDE_RIGHT, SIDE_TOP, SIDE_LEFT, SIDE_BOTTOM };
408 std::vector<SIDE> sides( sides_init, sides_init + arrayDim( sides_init ) );
409 std::vector<SIDE_AND_COLL> colliding;
410
411 // Iterate over all sides and find the ones that collide
412 for( SIDE side : sides )
413 {
414 SIDE_AND_NPINS sideandpins;
415 sideandpins.side = side;
416 sideandpins.pins = pinsOnSide( side );
417
418 BOX2I box( fieldBoxPlacement( sideandpins ), m_fbox_size );
419
420 COLLISION collision = COLLIDE_NONE;
421
422 for( SCH_ITEM* collider : filterCollisions( box ) )
423 {
424 SCH_LINE* line = dynamic_cast<SCH_LINE*>( collider );
425
426 if( line && !side.x )
427 {
428 VECTOR2I start = line->GetStartPoint(), end = line->GetEndPoint();
429
430 if( start.y == end.y && collision != COLLIDE_OBJECTS )
431 collision = COLLIDE_H_WIRES;
432 else
433 collision = COLLIDE_OBJECTS;
434 }
435 else
436 {
437 collision = COLLIDE_OBJECTS;
438 }
439 }
440
441 if( collision != COLLIDE_NONE )
442 colliding.push_back( { side, collision } );
443 }
444
445 return colliding;
446 }
447
452 SIDE_AND_NPINS chooseSideFiltered( std::vector<SIDE_AND_NPINS>& aSides,
453 const std::vector<SIDE_AND_COLL>& aCollidingSides,
454 COLLISION aCollision,
455 SIDE_AND_NPINS aLastSelection)
456 {
457 SIDE_AND_NPINS sel = aLastSelection;
458
459 std::vector<SIDE_AND_NPINS>::iterator it = aSides.begin();
460
461 while( it != aSides.end() )
462 {
463 bool collide = false;
464
465 for( SIDE_AND_COLL collision : aCollidingSides )
466 {
467 if( collision.side == it->side && collision.collision == aCollision )
468 collide = true;
469 }
470
471 if( !collide )
472 {
473 ++it;
474 }
475 else
476 {
477 if( it->pins <= sel.pins )
478 {
479 sel.pins = it->pins;
480 sel.side = it->side;
481 }
482
483 it = aSides.erase( it );
484 }
485 }
486
487 return sel;
488 }
489
495 SIDE_AND_NPINS chooseSideForFields( bool aAvoidCollisions )
496 {
497 std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
498
499 std::reverse( sides.begin(), sides.end() );
500 SIDE_AND_NPINS side = { VECTOR2I( 1, 0 ), UINT_MAX };
501
502 if( aAvoidCollisions )
503 {
504 std::vector<SIDE_AND_COLL> colliding_sides = getCollidingSides();
505 side = chooseSideFiltered( sides, colliding_sides, COLLIDE_OBJECTS, side );
506 side = chooseSideFiltered( sides, colliding_sides, COLLIDE_H_WIRES, side );
507 }
508
509 for( SIDE_AND_NPINS& each_side : sides | boost::adaptors::reversed )
510 {
511 if( !each_side.pins ) return each_side;
512 }
513
514 for( SIDE_AND_NPINS& each_side : sides )
515 {
516 if( each_side.pins <= side.pins )
517 {
518 side.pins = each_side.pins;
519 side.side = each_side.side;
520 }
521 }
522
523 return side;
524 }
525
531 void justifyField( SCH_FIELD* aField, SIDE aFieldSide )
532 {
533 // Justification is set twice to allow IsHorizJustifyFlipped() to work correctly.
534 aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x ) );
535 aField->SetHorizJustify( TO_HJUSTIFY( -aFieldSide.x
536 * ( aField->IsHorizJustifyFlipped() ? -1 : 1 ) ) );
538 }
539
544 {
545 VECTOR2I fbox_center = m_symbol_bbox.Centre();
546 int offs_x = ( m_symbol_bbox.GetWidth() + m_fbox_size.x ) / 2;
547 int offs_y = ( m_symbol_bbox.GetHeight() + m_fbox_size.y ) / 2;
548
549 if( aFieldSideAndPins.side.x != 0 )
550 offs_x += HPADDING;
551 else if( aFieldSideAndPins.side.y != 0 )
552 offs_y += VPADDING;
553
554 fbox_center.x += aFieldSideAndPins.side.x * offs_x;
555 fbox_center.y += aFieldSideAndPins.side.y * offs_y;
556
557 int x = fbox_center.x - ( m_fbox_size.x / 2 );
558 int y = fbox_center.y - ( m_fbox_size.y / 2 );
559
560 auto getPinsBox =
561 [&]( const VECTOR2I& aSide )
562 {
563 BOX2I pinsBox;
564
565 for( SCH_PIN* each_pin : m_symbol->GetPins() )
566 {
567 if( !each_pin->IsVisible() && !m_is_power_symbol )
568 continue;
569
570 if( getPinSide( each_pin ) == aSide )
571 pinsBox.Merge( each_pin->GetBoundingBox() );
572 }
573
574 return pinsBox;
575 };
576
577 if( aFieldSideAndPins.pins > 0 )
578 {
579 BOX2I pinsBox = getPinsBox( aFieldSideAndPins.side );
580
581 if( aFieldSideAndPins.side == SIDE_TOP || aFieldSideAndPins.side == SIDE_BOTTOM )
582 {
583 x = pinsBox.GetRight() + ( HPADDING * 2 );
584 }
585 else if( aFieldSideAndPins.side == SIDE_RIGHT || aFieldSideAndPins.side == SIDE_LEFT )
586 {
587 y = pinsBox.GetTop() - ( m_fbox_size.y + ( VPADDING * 2 ) );
588 }
589 }
590
591 return VECTOR2I( x, y );
592 }
593
598 bool fitFieldsBetweenWires( BOX2I* aBox, SIDE aSide )
599 {
600 if( aSide != SIDE_TOP && aSide != SIDE_BOTTOM )
601 return false;
602
603 std::vector<SCH_ITEM*> colliders = filterCollisions( *aBox );
604
605 if( colliders.empty() )
606 return false;
607
608 // Find the offset of the wires for proper positioning
609 int offset = 0;
610
611 for( SCH_ITEM* item : colliders )
612 {
613 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
614
615 if( !line )
616 return false;
617
618 VECTOR2I start = line->GetStartPoint(), end = line->GetEndPoint();
619
620 if( start.y != end.y )
621 return false;
622
623 int this_offset = (3 * WIRE_V_SPACING / 2) - ( start.y % WIRE_V_SPACING );
624
625 if( offset == 0 )
626 offset = this_offset;
627 else if( offset != this_offset )
628 return false;
629 }
630
631 // At this point we are recomputing the field box size. Do not
632 // return false after this point.
633 m_fbox_size = computeFBoxSize( /* aDynamic */ false );
634
635 VECTOR2I pos = aBox->GetPosition();
636
637 pos.y = round_n( pos.y, WIRE_V_SPACING, aSide == SIDE_BOTTOM );
638
639 aBox->SetOrigin( pos );
640 return true;
641 }
642
651 int fieldHPlacement( SCH_FIELD* aField, const BOX2I& aFieldBox )
652 {
653 int field_hjust;
654 int field_xcoord;
655
656 if( aField->IsHorizJustifyFlipped() )
657 field_hjust = -aField->GetHorizJustify();
658 else
659 field_hjust = aField->GetHorizJustify();
660
661 switch( field_hjust )
662 {
664 field_xcoord = aFieldBox.GetLeft();
665 break;
667 field_xcoord = aFieldBox.Centre().x;
668 break;
670 field_xcoord = aFieldBox.GetRight();
671 break;
672 default:
673 wxFAIL_MSG( "Unexpected value for SCH_FIELD::GetHorizJustify()" );
674 field_xcoord = aFieldBox.Centre().x; // Most are centered
675 }
676
677 return field_xcoord;
678 }
679
691 int fieldVPlacement( SCH_FIELD* aField, const BOX2I& aFieldBox, int* aAccumulatedPosition,
692 bool aDynamic )
693 {
694 int field_height;
695 int padding;
696
697 if( !aDynamic )
698 {
699 field_height = WIRE_V_SPACING / 2;
700 padding = WIRE_V_SPACING / 2;
701 }
702 else if( m_align_to_grid )
703 {
704 field_height = aField->GetBoundingBox().GetHeight();
705 padding = round_n( field_height, schIUScale.MilsToIU( 50 ), true ) - field_height;
706 }
707 else
708 {
709 field_height = aField->GetBoundingBox().GetHeight();
710 padding = FIELD_PADDING;
711 }
712
713 int placement = *aAccumulatedPosition + padding / 2 + field_height / 2;
714
715 *aAccumulatedPosition += padding + field_height;
716
717 return placement;
718 }
719
720private:
723 std::vector<SCH_FIELD*> m_fields;
724 std::vector<SCH_ITEM*> m_colliders;
730};
731
732
737
738
739void SCH_SYMBOL::AutoplaceFields( SCH_SCREEN* aScreen, bool aManual )
740{
741 if( aManual )
742 wxASSERT_MSG( aScreen, "A SCH_SCREEN pointer must be given for manual autoplacement" );
743
744 AUTOPLACER autoplacer( this, aScreen );
745 autoplacer.DoAutoplace( aManual );
747}
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:111
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.
void DoAutoplace(bool aManual)
Do the actual autoplacement.
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.
AUTOPLACER(SCH_SYMBOL *aSymbol, SCH_SCREEN *aScreen)
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...
SCH_SYMBOL * m_symbol
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.
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 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...
void SetOrigin(const Vec &pos)
Definition: box2.h:202
const Vec & GetPosition() const
Definition: box2.h:184
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
coord_type GetTop() const
Definition: box2.h:194
coord_type GetHeight() const
Definition: box2.h:188
coord_type GetWidth() const
Definition: box2.h:187
Vec Centre() const
Definition: box2.h:70
coord_type GetRight() const
Definition: box2.h:189
coord_type GetLeft() const
Definition: box2.h:193
BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition: box2.h:588
virtual bool IsVisible() const
Definition: eda_text.h:129
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition: eda_text.cpp:248
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition: eda_text.h:142
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition: eda_text.cpp:240
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:243
APP_SETTINGS_BASE * KifaceSettings() const
Definition: kiface_base.h:93
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:909
Instances are attached to a symbol or sheet and provide a place for the symbol's value,...
Definition: sch_field.h:50
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_field.cpp:462
bool IsHorizJustifyFlipped() const
Return whether the field will be rendered with the horizontal justification inverted due to rotation ...
Definition: sch_field.cpp:504
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_field.cpp:1050
bool CanAutoplace() const
Definition: sch_field.h:152
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
FIELDS_AUTOPLACED m_fieldsAutoplaced
Definition: sch_item.h:493
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
VECTOR2I GetEndPoint() const
Definition: sch_line.h:137
VECTOR2I GetStartPoint() const
Definition: sch_line.h:132
LIB_PIN * GetLibPin() const
Definition: sch_pin.h:59
EE_RTREE & Items()
Gets the full RTree, usually for iterating.
Definition: sch_screen.h:109
Schematic symbol object.
Definition: sch_symbol.h:80
void AutoplaceFields(SCH_SCREEN *aScreen, bool aManual) override
Automatically orient all the fields in the symbol.
bool IsInNetlist() const
std::vector< SCH_PIN * > GetPins(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve a list of the SCH_PINs for the given sheet path.
TRANSFORM & GetTransform()
Definition: sch_symbol.h:275
int GetOrientation() const
Get the display symbol orientation.
BOX2I GetBodyAndPinsBoundingBox() const
Return a bounding box for the symbol body and pins but not the fields.
void GetFields(std::vector< SCH_FIELD * > &aVector, bool aVisibleOnly)
Populate a std::vector with SCH_FIELDs.
Definition: sch_symbol.cpp:931
BOX2I GetBodyBoundingBox() const
Return a bounding box for the symbol body but not the pins or fields.
int y1
Definition: transform.h:50
static constexpr EDA_ANGLE & ANGLE_HORIZONTAL
Definition: eda_angle.h:408
static constexpr EDA_ANGLE & ANGLE_VERTICAL
Definition: eda_angle.h:409
@ PIN_LEFT
Definition: lib_pin.h:46
@ PIN_RIGHT
Definition: lib_pin.h:45
@ PIN_UP
Definition: lib_pin.h:47
@ PIN_DOWN
Definition: lib_pin.h:48
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
@ SYM_ORIENT_270
@ SYM_ORIENT_180
@ SYM_MIRROR_X
@ SYM_ORIENT_90
@ SYM_ORIENT_0
@ FIELDS_AUTOPLACED_AUTO
Definition: sch_item.h:57
@ FIELDS_AUTOPLACED_MANUAL
Definition: sch_item.h:58
bool collide(T aObject, U aAnotherObject, int aMinDistance)
Used by SHAPE_INDEX to implement Query().
Definition: shape_index.h:114
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_CENTER
#define TO_HJUSTIFY(x)
VECTOR2< int > VECTOR2I
Definition: vector2d.h:618