KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The KiCad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25/******************************************************************************
26 * Field autoplacer: Tries to find an optimal place for symbol fields, and places them there.
27 * There are two modes: "auto"-autoplace, and "manual" autoplace.
28 * Auto mode is for when the process is run automatically, like when rotating parts, and it
29 * avoids doing things that would be helpful for the final positioning but annoying if they
30 * happened without permission.
31 * Short description of the process:
32 *
33 * 1. Compute the dimensions of the fields' bounding box ::computeFBoxSize
34 * 2. Determine which side the fields will go on. ::chooseSideForFields
35 * 1. Sort the four sides in preference order,
36 * depending on the symbol's shape and
37 * orientation ::getPreferredSides
38 * 2. If in manual mode, sift out the sides that would
39 * cause fields to overlap other items ::getCollidingSides
40 * 3. If any remaining sides have zero pins there,
41 * choose the highest zero-pin side according to
42 * preference order.
43 * 4. If all sides have pins, choose the side with the
44 * fewest pins.
45 * 3. Compute the position of the fields' bounding box ::fieldBoxPlacement
46 * 4. In manual mode, shift the box vertically if possible
47 * to fit fields between adjacent wires ::fitFieldsBetweenWires
48 * 5. Move all fields to their final positions
49 * 1. Re-justify fields if options allow that ::justifyField
50 * 2. Round to a 50-mil grid coordinate if desired
51 */
52
53#include <boost/range/adaptor/reversed.hpp>
54
56#include <sch_edit_frame.h>
57#include <sch_line.h>
58#include <kiface_base.h>
59#include <algorithm>
60#include <tool/tool_manager.h>
61#include <core/arraydim.h>
62
63#define FIELD_PADDING schIUScale.MilsToIU( 15 ) // arbitrarily chosen for aesthetics
64#define WIRE_V_SPACING schIUScale.MilsToIU( 100 )
65#define HPADDING schIUScale.MilsToIU( 25 ) // arbitrarily chosen for aesthetics
66#define VPADDING schIUScale.MilsToIU( 15 ) // arbitrarily chosen for aesthetics
67
71template<typename T> T round_n( const T& value, const T& n, bool aRoundUp )
72{
73 if( value % n )
74 return n * (value / n + (aRoundUp ? 1 : 0));
75 else
76 return value;
77}
78
79
81{
82public:
83 typedef VECTOR2I SIDE;
86
88 {
90 unsigned pins;
91 };
92
98
99 AUTOPLACER( SYMBOL* aSymbol, SCH_SCREEN* aScreen ) :
100 m_screen( aScreen ),
101 m_symbol( aSymbol ),
102 m_is_power_symbol( false )
103 {
104 m_symbol->GetFields( m_fields, /* aVisibleOnly */ true );
105
106 auto cfg = dynamic_cast<EESCHEMA_SETTINGS*>( Kiface().KifaceSettings() );
107 wxASSERT( cfg );
108
109 m_allow_rejustify = false;
110 m_align_to_grid = true;
111
112 if( cfg )
113 {
114 m_allow_rejustify = cfg->m_AutoplaceFields.allow_rejustify;
115 m_align_to_grid = cfg->m_AutoplaceFields.align_to_grid;
116 }
117
118 // Fields always display horizontally after autoplace. For 90/270 rotated
119 // symbols, GetDrawRotation() flips the stored angle, so we store VERTICAL
120 // to counteract the transform and produce horizontal display.
121 m_field_angle = m_symbol->GetTransform().y1 ? ANGLE_VERTICAL : ANGLE_HORIZONTAL;
122
123 m_symbol_bbox = m_symbol->GetBodyBoundingBox();
124 m_fbox_size = computeFBoxSize( /* aDynamic */ true );
125
126 if( SCH_SYMBOL* schSymbol = dynamic_cast<SCH_SYMBOL*>( m_symbol ) )
127 m_is_power_symbol = !schSymbol->IsInNetlist();
128
129 if( aScreen )
131 }
132
139 {
140 bool forceWireSpacing = false;
141 SIDE_AND_NPINS sideandpins = chooseSideForFields( aAlgo == AUTOPLACE_MANUAL );
142 SIDE field_side = sideandpins.side;
143 VECTOR2I fbox_pos = fieldBoxPlacement( sideandpins );
144 BOX2I field_box( fbox_pos, m_fbox_size );
145
146 if( aAlgo == AUTOPLACE_MANUAL )
147 forceWireSpacing = fitFieldsBetweenWires( &field_box, field_side );
148
149 // Move the fields
150 int last_y_coord = field_box.GetTop();
151
152 for( SCH_FIELD* field : m_fields )
153 {
154 if( !field->IsVisible() || !field->CanAutoplace() )
155 continue;
156
157 field->SetTextAngle( m_field_angle );
158
160 {
161 if( sideandpins.pins > 0 )
162 {
163 if( field_side == SIDE_TOP || field_side == SIDE_BOTTOM )
164 justifyField( field, SIDE_RIGHT );
165 else
166 justifyField( field, SIDE_TOP );
167 }
168 else
169 {
170 justifyField( field, field_side );
171 }
172 }
173
174 VECTOR2I pos( fieldHPlacement( field, field_box ),
175 fieldVPlacement( field, field_box, &last_y_coord, !forceWireSpacing ) );
176
177 if( m_align_to_grid )
178 {
179 if( abs( field_side.x ) > 0 )
180 pos.x = round_n( pos.x, schIUScale.MilsToIU( 50 ), field_side.x >= 0 );
181
182 if( abs( field_side.y ) > 0 )
183 pos.y = round_n( pos.y, schIUScale.MilsToIU( 50 ), field_side.y >= 0 );
184 }
185
186 field->SetPosition( pos );
187 }
188 }
189
190protected:
195 VECTOR2I computeFBoxSize( bool aDynamic )
196 {
197 int max_field_width = 0;
198 int total_height = 0;
199
200 for( SCH_FIELD* field : m_fields )
201 {
202 if( !field->IsVisible() || !field->CanAutoplace() )
203 {
204 continue;
205 }
206
207 // GetBoundingBox() applies both the field's text angle and the symbol
208 // transform. Set the display angle so the combined rotation produces
209 // bounding box dimensions matching the final horizontal display, then
210 // restore the original angle.
211 EDA_ANGLE savedAngle = field->GetTextAngle();
212 field->SetTextAngle( m_field_angle );
213 BOX2I bbox = field->GetBoundingBox();
214 field->SetTextAngle( savedAngle );
215 int field_width = bbox.GetWidth();
216 int field_height = bbox.GetHeight();
217
218 max_field_width = std::max( max_field_width, field_width );
219
220 if( !aDynamic )
221 total_height += WIRE_V_SPACING;
222 else if( m_align_to_grid )
223 total_height += round_n( field_height, schIUScale.MilsToIU( 50 ), true );
224 else
225 total_height += field_height + FIELD_PADDING;
226 }
227
228 return VECTOR2I( max_field_width, total_height );
229 }
230
235 {
236 PIN_ORIENTATION pin_orient = aPin->PinDrawOrient( m_symbol->GetTransform() );
237
238 switch( pin_orient )
239 {
244 default:
245 wxFAIL_MSG( wxS( "Invalid pin orientation" ) );
246 return SIDE_LEFT;
247 }
248 }
249
253 unsigned pinsOnSide( SIDE aSide )
254 {
255 unsigned pin_count = 0;
256
257 for( SCH_PIN* each_pin : m_symbol->GetPins() )
258 {
259 if( !each_pin->IsVisible() && !m_is_power_symbol )
260 continue;
261
262 if( getPinSide( each_pin ) == aSide )
263 ++pin_count;
264 }
265
266 return pin_count;
267 }
268
273 void getPossibleCollisions( std::vector<SCH_ITEM*>& aItems )
274 {
275 wxCHECK_RET( m_screen, wxS( "getPossibleCollisions() with null m_screen" ) );
276
277 BOX2I symbolBox = m_symbol->GetBodyAndPinsBoundingBox();
278 std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
279
280 for( SIDE_AND_NPINS& side : sides )
281 {
282 BOX2I box( fieldBoxPlacement( side ), m_fbox_size );
283 box.Merge( symbolBox );
284
285 for( SCH_ITEM* item : m_screen->Items().Overlapping( box ) )
286 {
287 if( SCH_SYMBOL* candidate = dynamic_cast<SCH_SYMBOL*>( item ) )
288 {
289 if( candidate == m_symbol )
290 continue;
291
292 std::vector<SCH_FIELD*> fields;
293 candidate->GetFields( fields, /* aVisibleOnly */ true );
294
295 for( SCH_FIELD* field : fields )
296 aItems.push_back( field );
297 }
298
299 aItems.push_back( item );
300 }
301 }
302 }
303
308 std::vector<SCH_ITEM*> filterCollisions( const BOX2I& aRect )
309 {
310 std::vector<SCH_ITEM*> filtered;
311
312 for( SCH_ITEM* item : m_colliders )
313 {
314 BOX2I item_box;
315
316 if( SCH_SYMBOL* item_comp = dynamic_cast<SCH_SYMBOL*>( item ) )
317 item_box = item_comp->GetBodyAndPinsBoundingBox();
318 else
319 item_box = item->GetBoundingBox();
320
321 if( item_box.Intersects( aRect ) )
322 filtered.push_back( item );
323 }
324
325 return filtered;
326 }
327
332 std::vector<SIDE_AND_NPINS> getPreferredSides()
333 {
334 SIDE_AND_NPINS sides_init[] = {
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
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 }
395
400 {
401 if( !m_screen )
402 return BOX2I();
403
404 const PAGE_INFO& pageInfo = m_screen->GetPageSettings();
406
407 int pageWidth = pageInfo.GetWidthIU( schIUScale.IU_PER_MILS );
408 int pageHeight = pageInfo.GetHeightIU( schIUScale.IU_PER_MILS );
409
410 int leftMargin = schIUScale.mmToIU( dsModel.GetLeftMargin() );
411 int rightMargin = schIUScale.mmToIU( dsModel.GetRightMargin() );
412 int topMargin = schIUScale.mmToIU( dsModel.GetTopMargin() );
413 int bottomMargin = schIUScale.mmToIU( dsModel.GetBottomMargin() );
414
415 BOX2I drawableArea;
416 drawableArea.SetOrigin( leftMargin, topMargin );
417 drawableArea.SetEnd( pageWidth - rightMargin, pageHeight - bottomMargin );
418
419 return drawableArea;
420 }
421
425 std::vector<SIDE_AND_COLL> getCollidingSides()
426 {
427 SIDE sides_init[] = { SIDE_RIGHT, SIDE_TOP, SIDE_LEFT, SIDE_BOTTOM };
428 std::vector<SIDE> sides( sides_init, sides_init + arrayDim( sides_init ) );
429 std::vector<SIDE_AND_COLL> colliding;
430
431 BOX2I drawableArea = getDrawableArea();
432 bool checkDrawableArea = ( drawableArea.GetWidth() > 0 && drawableArea.GetHeight() > 0 );
433
434 // Iterate over all sides and find the ones that collide
435 for( SIDE side : sides )
436 {
437 SIDE_AND_NPINS sideandpins;
438 sideandpins.side = side;
439 sideandpins.pins = pinsOnSide( side );
440
441 BOX2I box( fieldBoxPlacement( sideandpins ), m_fbox_size );
442
443 COLLISION collision = COLLIDE_NONE;
444
445 // Check collision with drawing sheet boundary
446 if( checkDrawableArea && !drawableArea.Contains( box ) )
447 collision = COLLIDE_OBJECTS;
448
449 for( SCH_ITEM* collider : filterCollisions( box ) )
450 {
451 SCH_LINE* line = dynamic_cast<SCH_LINE*>( collider );
452
453 if( line && !side.x )
454 {
455 VECTOR2I start = line->GetStartPoint(), end = line->GetEndPoint();
456
457 if( start.y == end.y && collision != COLLIDE_OBJECTS )
458 collision = COLLIDE_H_WIRES;
459 else
460 collision = COLLIDE_OBJECTS;
461 }
462 else
463 {
464 collision = COLLIDE_OBJECTS;
465 }
466 }
467
468 if( collision != COLLIDE_NONE )
469 colliding.push_back( { side, collision } );
470 }
471
472 return colliding;
473 }
474
479 SIDE_AND_NPINS chooseSideFiltered( std::vector<SIDE_AND_NPINS>& aSides,
480 const std::vector<SIDE_AND_COLL>& aCollidingSides,
481 COLLISION aCollision,
482 SIDE_AND_NPINS aLastSelection)
483 {
484 SIDE_AND_NPINS sel = aLastSelection;
485
486 std::vector<SIDE_AND_NPINS>::iterator it = aSides.begin();
487
488 while( it != aSides.end() )
489 {
490 bool collide = false;
491
492 for( SIDE_AND_COLL collision : aCollidingSides )
493 {
494 if( collision.side == it->side && collision.collision == aCollision )
495 collide = true;
496 }
497
498 if( !collide )
499 {
500 ++it;
501 }
502 else
503 {
504 if( it->pins <= sel.pins )
505 {
506 sel.pins = it->pins;
507 sel.side = it->side;
508 }
509
510 it = aSides.erase( it );
511 }
512 }
513
514 return sel;
515 }
516
522 SIDE_AND_NPINS chooseSideForFields( bool aAvoidCollisions )
523 {
524 std::vector<SIDE_AND_NPINS> sides = getPreferredSides();
525
526 std::reverse( sides.begin(), sides.end() );
527 SIDE_AND_NPINS side = { VECTOR2I( 1, 0 ), UINT_MAX };
528
529 if( aAvoidCollisions )
530 {
531 std::vector<SIDE_AND_COLL> colliding_sides = getCollidingSides();
532 side = chooseSideFiltered( sides, colliding_sides, COLLIDE_OBJECTS, side );
533 side = chooseSideFiltered( sides, colliding_sides, COLLIDE_H_WIRES, side );
534 }
535
536 for( SIDE_AND_NPINS& each_side : sides | boost::adaptors::reversed )
537 {
538 if( !each_side.pins ) return each_side;
539 }
540
541 for( SIDE_AND_NPINS& each_side : sides )
542 {
543 if( each_side.pins <= side.pins )
544 {
545 side.pins = each_side.pins;
546 side.side = each_side.side;
547 }
548 }
549
550 return side;
551 }
552
558 void justifyField( SCH_FIELD* aField, SIDE aFieldSide )
559 {
560 // Justification is set twice to allow IsHorizJustifyFlipped() to work correctly.
561 aField->SetHorizJustify( ToHAlignment( -aFieldSide.x ) );
562 if( aField->IsHorizJustifyFlipped() )
564
566 }
567
572 {
573 VECTOR2I fbox_center = m_symbol_bbox.Centre();
574 int offs_x = ( m_symbol_bbox.GetWidth() + m_fbox_size.x ) / 2;
575 int offs_y = ( m_symbol_bbox.GetHeight() + m_fbox_size.y ) / 2;
576
577 if( aFieldSideAndPins.side.x != 0 )
578 offs_x += HPADDING;
579 else if( aFieldSideAndPins.side.y != 0 )
580 offs_y += VPADDING;
581
582 fbox_center.x += aFieldSideAndPins.side.x * offs_x;
583 fbox_center.y += aFieldSideAndPins.side.y * offs_y;
584
585 int x = fbox_center.x - ( m_fbox_size.x / 2 );
586 int y = fbox_center.y - ( m_fbox_size.y / 2 );
587
588 auto getPinsBox =
589 [&]( const VECTOR2I& aSide )
590 {
591 BOX2I pinsBox;
592
593 for( SCH_PIN* each_pin : m_symbol->GetPins() )
594 {
595 if( !each_pin->IsVisible() && !m_is_power_symbol )
596 continue;
597
598 if( getPinSide( each_pin ) == aSide )
599 pinsBox.Merge( each_pin->GetBoundingBox() );
600 }
601
602 return pinsBox;
603 };
604
605 if( aFieldSideAndPins.pins > 0 )
606 {
607 BOX2I pinsBox = getPinsBox( aFieldSideAndPins.side );
608
609 if( aFieldSideAndPins.side == SIDE_TOP || aFieldSideAndPins.side == SIDE_BOTTOM )
610 {
611 x = pinsBox.GetRight() + ( HPADDING * 2 );
612 }
613 else if( aFieldSideAndPins.side == SIDE_RIGHT || aFieldSideAndPins.side == SIDE_LEFT )
614 {
615 y = pinsBox.GetTop() - ( m_fbox_size.y + ( VPADDING * 2 ) );
616 }
617 }
618
619 return VECTOR2I( x, y );
620 }
621
626 bool fitFieldsBetweenWires( BOX2I* aBox, SIDE aSide )
627 {
628 if( aSide != SIDE_TOP && aSide != SIDE_BOTTOM )
629 return false;
630
631 std::vector<SCH_ITEM*> colliders = filterCollisions( *aBox );
632
633 if( colliders.empty() )
634 return false;
635
636 // Find the offset of the wires for proper positioning
637 int offset = 0;
638
639 for( SCH_ITEM* item : colliders )
640 {
641 SCH_LINE* line = dynamic_cast<SCH_LINE*>( item );
642
643 if( !line )
644 return false;
645
646 VECTOR2I start = line->GetStartPoint(), end = line->GetEndPoint();
647
648 if( start.y != end.y )
649 return false;
650
651 int this_offset = (3 * WIRE_V_SPACING / 2) - ( start.y % WIRE_V_SPACING );
652
653 if( offset == 0 )
654 offset = this_offset;
655 else if( offset != this_offset )
656 return false;
657 }
658
659 // At this point we are recomputing the field box size. Do not
660 // return false after this point.
661 m_fbox_size = computeFBoxSize( /* aDynamic */ false );
662
663 VECTOR2I pos = aBox->GetPosition();
664
665 pos.y = round_n( pos.y, WIRE_V_SPACING, aSide == SIDE_BOTTOM );
666
667 aBox->SetOrigin( pos );
668 return true;
669 }
670
679 int fieldHPlacement( SCH_FIELD* aField, const BOX2I& aFieldBox )
680 {
681 int field_hjust;
682 int field_xcoord;
683
684 if( aField->IsHorizJustifyFlipped() )
685 field_hjust = -aField->GetHorizJustify();
686 else
687 field_hjust = aField->GetHorizJustify();
688
689 switch( field_hjust )
690 {
692 field_xcoord = aFieldBox.GetLeft();
693 break;
695 field_xcoord = aFieldBox.Centre().x;
696 break;
698 field_xcoord = aFieldBox.GetRight();
699 break;
700 default:
701 wxFAIL_MSG( wxS( "Unexpected value for SCH_FIELD::GetHorizJustify()" ) );
702 field_xcoord = aFieldBox.Centre().x; // Most are centered
703 }
704
705 return field_xcoord;
706 }
707
719 int fieldVPlacement( SCH_FIELD* aField, const BOX2I& aFieldBox, int* aAccumulatedPosition,
720 bool aDynamic )
721 {
722 int field_height;
723 int padding;
724
725 if( !aDynamic )
726 {
727 field_height = WIRE_V_SPACING / 2;
728 padding = WIRE_V_SPACING / 2;
729 }
730 else if( m_align_to_grid )
731 {
732 field_height = aField->GetBoundingBox().GetHeight();
733 padding = round_n( field_height, schIUScale.MilsToIU( 50 ), true ) - field_height;
734 }
735 else
736 {
737 field_height = aField->GetBoundingBox().GetHeight();
738 padding = FIELD_PADDING;
739 }
740
741 int placement = *aAccumulatedPosition + padding / 2 + field_height / 2;
742
743 *aAccumulatedPosition += padding + field_height;
744
745 return placement;
746 }
747
748private:
751 std::vector<SCH_FIELD*> m_fields;
752 std::vector<SCH_ITEM*> m_colliders;
759};
760
761
766
767
769{
770 if( aAlgo == AUTOPLACE_MANUAL )
771 wxASSERT_MSG( aScreen, wxS( "A SCH_SCREEN ptr must be given for manual autoplacement" ) );
772
773 AUTOPLACER autoplacer( this, aScreen );
774 autoplacer.DoAutoplace( aAlgo );
775
776 switch( aAlgo )
777 {
780 default: wxFAIL_MSG( "Unknown autoplace algorithm" ); break;
781 }
782}
783
784
786{
787 if( aAlgo == AUTOPLACE_MANUAL )
788 wxFAIL_MSG( wxS( "Manual autoplacement not supported for LIB_SYMBOLs" ) );
789
790 AUTOPLACER autoplacer( this, aScreen );
791 autoplacer.DoAutoplace( aAlgo );
792
793 switch( aAlgo )
794 {
797 default: wxFAIL_MSG( "Unknown autoplace algorithm" ); break;
798 }
799}
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:114
KIFACE_BASE & Kiface()
Global KIFACE_BASE "get" accessor.
BOX2< VECTOR2I > BOX2I
Definition box2.h:922
VECTOR2I computeFBoxSize(bool aDynamic)
Compute and return the size of the fields' bounding box.
VECTOR2I fieldBoxPlacement(SIDE_AND_NPINS aFieldSideAndPins)
Return the position of the field bounding box.
SIDE getPinSide(SCH_PIN *aPin)
Return the side that a pin is on.
int fieldVPlacement(SCH_FIELD *aField, const BOX2I &aFieldBox, int *aAccumulatedPosition, bool aDynamic)
Place a field vertically.
void getPossibleCollisions(std::vector< SCH_ITEM * > &aItems)
Populate a list of all drawing items that may collide with the fields.
static const SIDE SIDE_TOP
static const SIDE SIDE_BOTTOM
unsigned pinsOnSide(SIDE aSide)
Count the number of pins on a side of the symbol.
std::vector< SCH_FIELD * > m_fields
BOX2I getDrawableArea()
Compute the drawable area (inside the drawing sheet border) for collision detection.
SIDE_AND_NPINS chooseSideForFields(bool aAvoidCollisions)
Look where a symbol's pins are to pick a side to put the fields on.
bool fitFieldsBetweenWires(BOX2I *aBox, SIDE aSide)
Shift a field box up or down a bit to make the fields fit between some wires.
int fieldHPlacement(SCH_FIELD *aField, const BOX2I &aFieldBox)
Place a field horizontally, taking into account the field width and justification.
SCH_SCREEN * m_screen
std::vector< SCH_ITEM * > m_colliders
static const SIDE SIDE_RIGHT
std::vector< SCH_ITEM * > filterCollisions(const BOX2I &aRect)
Filter a list of possible colliders to include only those that actually collide with a given rectangl...
std::vector< SIDE_AND_NPINS > getPreferredSides()
Return a list with the preferred field sides for the symbol, in decreasing order of preference.
std::vector< SIDE_AND_COLL > getCollidingSides()
Return a list of the sides where a field set would collide with another item.
EDA_ANGLE m_field_angle
AUTOPLACER(SYMBOL *aSymbol, SCH_SCREEN *aScreen)
static const SIDE SIDE_LEFT
SIDE_AND_NPINS chooseSideFiltered(std::vector< SIDE_AND_NPINS > &aSides, const std::vector< SIDE_AND_COLL > &aCollidingSides, COLLISION aCollision, SIDE_AND_NPINS aLastSelection)
Choose a side for the fields, filtered on only one side collision type.
void DoAutoplace(AUTOPLACE_ALGO aAlgo)
Do the actual autoplacement.
void justifyField(SCH_FIELD *aField, SIDE aFieldSide)
Set the justification of a field based on the side it's supposed to be on, taking into account whethe...
constexpr const Vec & GetPosition() const
Definition box2.h:211
constexpr void SetOrigin(const Vec &pos)
Definition box2.h:237
constexpr size_type GetWidth() const
Definition box2.h:214
constexpr Vec Centre() const
Definition box2.h:97
constexpr BOX2< Vec > & Merge(const BOX2< Vec > &aRect)
Modify the position and size of the rectangle in order to contain aRect.
Definition box2.h:658
constexpr size_type GetHeight() const
Definition box2.h:215
constexpr coord_type GetLeft() const
Definition box2.h:228
constexpr bool Contains(const Vec &aPoint) const
Definition box2.h:168
constexpr coord_type GetRight() const
Definition box2.h:217
constexpr void SetEnd(coord_type x, coord_type y)
Definition box2.h:297
constexpr coord_type GetTop() const
Definition box2.h:229
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition box2.h:311
Handle the graphic items list to draw/plot the frame and title block.
double GetRightMargin()
static DS_DATA_MODEL & GetTheInstance()
Return the instance of DS_DATA_MODEL used in the application.
double GetTopMargin()
double GetBottomMargin()
double GetLeftMargin()
void SetVertJustify(GR_TEXT_V_ALIGN_T aType)
Definition eda_text.cpp:431
GR_TEXT_H_ALIGN_T GetHorizJustify() const
Definition eda_text.h:200
void SetHorizJustify(GR_TEXT_H_ALIGN_T aType)
Definition eda_text.cpp:423
APP_SETTINGS_BASE * KifaceSettings() const
Definition kiface_base.h:95
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Automatically orient all the fields in the symbol.
Describe the page size and margins of a paper page on which to eventually print or plot.
Definition page_info.h:79
int GetHeightIU(double aIUScale) const
Gets the page height in IU.
Definition page_info.h:168
int GetWidthIU(double aIUScale) const
Gets the page width in IU.
Definition page_info.h:159
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
bool IsHorizJustifyFlipped() const
Return whether the field will be rendered with the horizontal justification inverted due to rotation ...
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition sch_item.h:168
AUTOPLACE_ALGO m_fieldsAutoplaced
Definition sch_item.h:782
Segment description base class to describe items which have 2 end points (track, wire,...
Definition sch_line.h:42
VECTOR2I GetEndPoint() const
Definition sch_line.h:148
VECTOR2I GetStartPoint() const
Definition sch_line.h:139
PIN_ORIENTATION PinDrawOrient(const TRANSFORM &aTransform) const
Return the pin real orientation (PIN_UP, PIN_DOWN, PIN_RIGHT, PIN_LEFT), according to its orientation...
Definition sch_pin.cpp:1196
Schematic symbol object.
Definition sch_symbol.h:76
void AutoplaceFields(SCH_SCREEN *aScreen, AUTOPLACE_ALGO aAlgo) override
Automatically orient all the fields in the symbol.
A base class for LIB_SYMBOL and SCH_SYMBOL.
Definition symbol.h:63
static constexpr EDA_ANGLE ANGLE_VERTICAL
Definition eda_angle.h:408
static constexpr EDA_ANGLE ANGLE_HORIZONTAL
Definition eda_angle.h:407
PIN_ORIENTATION
The symbol library pin object orientations.
Definition pin_type.h:105
@ PIN_UP
The pin extends upwards from the connection point: Probably on the bottom side of the symbol.
Definition pin_type.h:127
@ PIN_RIGHT
The pin extends rightwards from the connection point.
Definition pin_type.h:111
@ PIN_LEFT
The pin extends leftwards from the connection point: Probably on the right side of the symbol.
Definition pin_type.h:118
@ PIN_DOWN
The pin extends downwards from the connection: Probably on the top side of the symbol.
Definition pin_type.h:135
AUTOPLACE_ALGO
Definition sch_item.h:69
@ AUTOPLACE_MANUAL
Definition sch_item.h:72
@ AUTOPLACE_AUTO
Definition sch_item.h:71
bool collide(T aObject, U aAnotherObject, int aLayer, int aMinDistance)
Used by SHAPE_INDEX to implement Query().
Definition shape_index.h:97
@ SYM_ORIENT_270
Definition symbol.h:42
@ SYM_ORIENT_180
Definition symbol.h:41
@ SYM_MIRROR_X
Definition symbol.h:43
@ SYM_ORIENT_90
Definition symbol.h:40
@ SYM_ORIENT_0
Definition symbol.h:39
VECTOR2I end
@ GR_TEXT_H_ALIGN_CENTER
@ GR_TEXT_H_ALIGN_RIGHT
@ GR_TEXT_H_ALIGN_LEFT
@ GR_TEXT_V_ALIGN_CENTER
constexpr GR_TEXT_H_ALIGN_T GetFlippedAlignment(GR_TEXT_H_ALIGN_T aAlign)
Get the reverse alignment: left-right are swapped, others are unchanged.
constexpr GR_TEXT_H_ALIGN_T ToHAlignment(int x)
Convert an integral value to horizontal alignment.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695