KiCad PCB EDA Suite
sch_line.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 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 1992-2023 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#include <base_units.h>
26#include <bitmaps.h>
27#include <string_utils.h>
28#include <core/mirror.h>
29#include <sch_painter.h>
30#include <plotters/plotter.h>
32#include <sch_line.h>
33#include <sch_edit_frame.h>
35#include <schematic.h>
36#include <connection_graph.h>
39#include <trigo.h>
40#include <board_item.h>
41
42
43SCH_LINE::SCH_LINE( const VECTOR2I& pos, int layer ) :
44 SCH_ITEM( nullptr, SCH_LINE_T )
45{
46 m_start = pos;
47 m_end = pos;
48 m_stroke.SetWidth( 0 );
50 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
51
52 switch( layer )
53 {
54 default: m_layer = LAYER_NOTES; break;
55 case LAYER_WIRE: m_layer = LAYER_WIRE; break;
56 case LAYER_BUS: m_layer = LAYER_BUS; break;
57 }
58
59 if( layer == LAYER_NOTES )
61 else
63
64 if( layer == LAYER_WIRE )
66 else if( layer == LAYER_BUS )
68 else
70
72 m_lastResolvedColor = COLOR4D::UNSPECIFIED;
73}
74
75
77 SCH_ITEM( aLine )
78{
79 m_start = aLine.m_start;
80 m_end = aLine.m_end;
81 m_stroke = aLine.m_stroke;
84
88
90}
91
92
93wxString SCH_LINE::GetNetname( const SCH_SHEET_PATH& aSheet )
94{
95 std::list<const SCH_LINE *> checkedLines;
96 checkedLines.push_back(this);
97 return FindWireSegmentNetNameRecursive( this, checkedLines, aSheet );
98}
99
100
102 std::list<const SCH_LINE *> &checkedLines,
103 const SCH_SHEET_PATH& aSheet ) const
104{
105 for ( auto connected : line->ConnectedItems( aSheet ) )
106 {
107 if( connected->Type() == SCH_LINE_T )
108 {
109 if( std::find(checkedLines.begin(), checkedLines.end(), connected ) == checkedLines.end() )
110 {
111 SCH_LINE* connectedLine = static_cast<SCH_LINE*>( connected );
112 checkedLines.push_back( connectedLine );
113
114 wxString netName = FindWireSegmentNetNameRecursive( connectedLine, checkedLines,
115 aSheet );
116
117 if( !netName.IsEmpty() )
118 return netName;
119 }
120 }
121 else if( connected->Type() == SCH_LABEL_T
122 || connected->Type() == SCH_GLOBAL_LABEL_T
123 || connected->Type() == SCH_DIRECTIVE_LABEL_T)
124 {
125 return static_cast<SCH_TEXT*>( connected )->GetText();
126 }
127
128 }
129 return "";
130}
131
132
134{
135 return new SCH_LINE( *this );
136}
137
138
139void SCH_LINE::Move( const VECTOR2I& aOffset )
140{
141 if( aOffset != VECTOR2I( 0, 0 ) )
142 {
143 m_start += aOffset;
144 m_end += aOffset;
145 SetModified();
146 }
147}
148
149
150void SCH_LINE::MoveStart( const VECTOR2I& aOffset )
151{
152 if( aOffset != VECTOR2I( 0, 0 ) )
153 {
154 m_start += aOffset;
155 SetModified();
156 }
157}
158
159
160void SCH_LINE::MoveEnd( const VECTOR2I& aOffset )
161{
162 if( aOffset != VECTOR2I( 0, 0 ) )
163 {
164 m_end += aOffset;
165 SetModified();
166 }
167}
168
169
170#if defined(DEBUG)
171
172void SCH_LINE::Show( int nestLevel, std::ostream& os ) const
173{
174 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
175 << " layer=\"" << m_layer << '"'
176 << " startIsDangling=\"" << m_startIsDangling
177 << '"' << " endIsDangling=\""
178 << m_endIsDangling << '"' << ">"
179 << " <start" << m_start << "/>"
180 << " <end" << m_end << "/>" << "</"
181 << GetClass().Lower().mb_str() << ">\n";
182}
183
184#endif
185
186
187void SCH_LINE::ViewGetLayers( int aLayers[], int& aCount ) const
188{
189 aCount = 4;
190 aLayers[0] = LAYER_DANGLING;
191 aLayers[1] = m_layer;
192 aLayers[2] = LAYER_SELECTION_SHADOWS;
193 aLayers[3] = LAYER_OP_VOLTAGES;
194}
195
196
197double SCH_LINE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
198{
199 constexpr double HIDE = std::numeric_limits<double>::max();
200 constexpr double SHOW = 0.0;
201
202 if( aLayer == LAYER_OP_VOLTAGES )
203 {
204 if( m_start == m_end )
205 return HIDE;
206
207 int height = std::abs( m_end.y - m_start.y );
208 int width = std::abs( m_end.x - m_start.x );
209
210 // Operating points will be shown only if zoom is appropriate
211 if( height == 0 )
212 return (double) schIUScale.mmToIU( 15 ) / width;
213 else
214 return (double) schIUScale.mmToIU( 5 ) / height;
215 }
216
217 // Other layers are always drawn.
218 return SHOW;
219}
220
221
223{
224 int width = GetPenWidth() / 2;
225
226 int xmin = std::min( m_start.x, m_end.x ) - width;
227 int ymin = std::min( m_start.y, m_end.y ) - width;
228
229 int xmax = std::max( m_start.x, m_end.x ) + width + 1;
230 int ymax = std::max( m_start.y, m_end.y ) + width + 1;
231
232 BOX2I ret( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin, ymax - ymin ) );
233
234 return ret;
235}
236
237
239{
240 return GetLineLength( m_start, m_end );
241}
242
243
244void SCH_LINE::SetLineColor( const COLOR4D& aColor )
245{
246 m_stroke.SetColor( aColor );
248}
249
250
251void SCH_LINE::SetLineColor( const double r, const double g, const double b, const double a )
252{
253 COLOR4D newColor(r, g, b, a);
254
255 if( newColor == COLOR4D::UNSPECIFIED )
256 {
257 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
258 }
259 else
260 {
261 // Eeschema does not allow alpha channel in colors
262 newColor.a = 1.0;
263 m_stroke.SetColor( newColor );
264 }
265}
266
267
269{
270 if( m_stroke.GetColor() != COLOR4D::UNSPECIFIED )
272 else if( !IsConnectable() )
273 m_lastResolvedColor = COLOR4D::UNSPECIFIED;
274 else if( !IsConnectivityDirty() )
275 m_lastResolvedColor = GetEffectiveNetClass()->GetSchematicColor();
276
277 return m_lastResolvedColor;
278}
279
280
281void SCH_LINE::SetLineStyle( const int aStyleId )
282{
283 SetLineStyle( static_cast<PLOT_DASH_TYPE>( aStyleId ) );
284}
285
286
288{
289 m_stroke.SetPlotStyle( aStyle );
291}
292
293
295{
297 return m_stroke.GetPlotStyle();
298
300}
301
302
304{
307 else if( !IsConnectable() )
309 else if( !IsConnectivityDirty() )
311
313}
314
315
316void SCH_LINE::SetLineWidth( const int aSize )
317{
318 m_stroke.SetWidth( aSize );
320}
321
322
324{
325 SCHEMATIC* schematic = Schematic();
326
327 switch ( m_layer )
328 {
329 default:
330 if( m_stroke.GetWidth() > 0 )
331 return m_stroke.GetWidth();
332
333 if( schematic )
334 return schematic->Settings().m_DefaultLineWidth;
335
337
338 case LAYER_WIRE:
339 if( m_stroke.GetWidth() > 0 )
341 else if( !IsConnectivityDirty() )
342 m_lastResolvedWidth = GetEffectiveNetClass()->GetWireWidth();
343
344 return m_lastResolvedWidth;
345
346 case LAYER_BUS:
347 if( m_stroke.GetWidth() > 0 )
349 else if( !IsConnectivityDirty() )
350 m_lastResolvedWidth = GetEffectiveNetClass()->GetBusWidth();
351
352 return m_lastResolvedWidth;
353 }
354}
355
356
357void SCH_LINE::Print( const RENDER_SETTINGS* aSettings, const VECTOR2I& offset )
358{
359 wxDC* DC = aSettings->GetPrintDC();
361
362 if( color == COLOR4D::UNSPECIFIED )
363 color = aSettings->GetLayerColor( GetLayer() );
364
365 VECTOR2I start = m_start;
366 VECTOR2I end = m_end;
368 int penWidth = std::max( GetPenWidth(), aSettings->GetDefaultPenWidth() );
369
370 if( lineStyle <= PLOT_DASH_TYPE::FIRST_TYPE )
371 {
372 GRLine( DC, start.x, start.y, end.x, end.y, penWidth, color );
373 }
374 else
375 {
376 SHAPE_SEGMENT segment( start, end );
377
378 STROKE_PARAMS::Stroke( &segment, lineStyle, penWidth, aSettings,
379 [&]( const VECTOR2I& a, const VECTOR2I& b )
380 {
381 GRLine( DC, a.x, a.y, b.x, b.y, penWidth, color );
382 } );
383 }
384}
385
386
387void SCH_LINE::MirrorVertically( int aCenter )
388{
389 if( m_flags & STARTPOINT )
390 MIRROR( m_start.y, aCenter );
391
392 if( m_flags & ENDPOINT )
393 MIRROR( m_end.y, aCenter );
394}
395
396
398{
399 if( m_flags & STARTPOINT )
400 MIRROR( m_start.x, aCenter );
401
402 if( m_flags & ENDPOINT )
403 MIRROR( m_end.x, aCenter );
404}
405
406
407void SCH_LINE::Rotate( const VECTOR2I& aCenter )
408{
409 // When we allow off grid items, the
410 // else if should become a plain if to allow
411 // rotation around the center of the line
412 if( m_flags & STARTPOINT )
413 RotatePoint( m_start, aCenter, ANGLE_90 );
414
415 else if( m_flags & ENDPOINT )
416 RotatePoint( m_end, aCenter, ANGLE_90 );
417}
418
419
420void SCH_LINE::RotateStart( const VECTOR2I& aCenter )
421{
422 RotatePoint( m_start, aCenter, ANGLE_90 );
423}
424
425
426void SCH_LINE::RotateEnd( const VECTOR2I& aCenter )
427{
428 RotatePoint( m_end, aCenter, ANGLE_90 );
429}
430
431
432int SCH_LINE::GetAngleFrom( const VECTOR2I& aPoint ) const
433{
434 VECTOR2I vec;
435
436 if( aPoint == m_start )
437 vec = m_end - aPoint;
438 else
439 vec = m_start - aPoint;
440
441 return KiROUND( EDA_ANGLE( vec ).AsDegrees() );
442}
443
444
445int SCH_LINE::GetReverseAngleFrom( const VECTOR2I& aPoint ) const
446{
447 VECTOR2I vec;
448
449 if( aPoint == m_end )
450 vec = m_start - aPoint;
451 else
452 vec = m_end - aPoint;
453
454 return KiROUND( EDA_ANGLE( vec ).AsDegrees() );
455}
456
457
458bool SCH_LINE::IsParallel( const SCH_LINE* aLine ) const
459{
460 wxCHECK_MSG( aLine != nullptr && aLine->Type() == SCH_LINE_T, false,
461 wxT( "Cannot test line segment for overlap." ) );
462
463 VECTOR2I firstSeg = m_end - m_start;
464 VECTOR2I secondSeg = aLine->m_end - aLine->m_start;
465
466 // Use long long here to avoid overflow in calculations
467 return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x );
468}
469
470
471SCH_LINE* SCH_LINE::MergeOverlap( SCH_SCREEN* aScreen, SCH_LINE* aLine, bool aCheckJunctions )
472{
473 auto less =
474 []( const VECTOR2I& lhs, const VECTOR2I& rhs ) -> bool
475 {
476 if( lhs.x == rhs.x )
477 return lhs.y < rhs.y;
478
479 return lhs.x < rhs.x;
480 };
481
482 wxCHECK_MSG( aLine != nullptr && aLine->Type() == SCH_LINE_T, nullptr,
483 wxT( "Cannot test line segment for overlap." ) );
484
485 if( this == aLine || GetLayer() != aLine->GetLayer() )
486 return nullptr;
487
488 VECTOR2I leftmost_start = aLine->m_start;
489 VECTOR2I leftmost_end = aLine->m_end;
490
491 VECTOR2I rightmost_start = m_start;
492 VECTOR2I rightmost_end = m_end;
493
494 // We place the start to the left and below the end of both lines
495 if( leftmost_start != std::min( { leftmost_start, leftmost_end }, less ) )
496 std::swap( leftmost_start, leftmost_end );
497 if( rightmost_start != std::min( { rightmost_start, rightmost_end }, less ) )
498 std::swap( rightmost_start, rightmost_end );
499
500 // - leftmost is the line that starts farthest to the left
501 // - other is the line that is _not_ leftmost
502 // - rightmost is the line that ends farthest to the right. This may or may not be 'other'
503 // as the second line may be completely covered by the first.
504 if( less( rightmost_start, leftmost_start ) )
505 {
506 std::swap( leftmost_start, rightmost_start );
507 std::swap( leftmost_end, rightmost_end );
508 }
509
510 VECTOR2I other_start = rightmost_start;
511 VECTOR2I other_end = rightmost_end;
512
513 if( less( rightmost_end, leftmost_end ) )
514 {
515 rightmost_start = leftmost_start;
516 rightmost_end = leftmost_end;
517 }
518
519 // If we end one before the beginning of the other, no overlap is possible
520 if( less( leftmost_end, other_start ) )
521 {
522 return nullptr;
523 }
524
525 // Search for a common end:
526 if( ( leftmost_start == other_start ) && ( leftmost_end == other_end ) ) // Trivial case
527 {
528 SCH_LINE* ret = new SCH_LINE( *aLine );
529 ret->SetStartPoint( leftmost_start );
530 ret->SetEndPoint( leftmost_end );
531 ret->SetConnectivityDirty( true );
532
533 if( IsSelected() || aLine->IsSelected() )
534 ret->SetSelected();
535
536 return ret;
537 }
538
539 bool colinear = false;
540
541 /* Test alignment: */
542 if( ( leftmost_start.y == leftmost_end.y ) &&
543 ( other_start.y == other_end.y ) ) // Horizontal segment
544 {
545 colinear = ( leftmost_start.y == other_start.y );
546 }
547 else if( ( leftmost_start.x == leftmost_end.x ) &&
548 ( other_start.x == other_end.x ) ) // Vertical segment
549 {
550 colinear = ( leftmost_start.x == other_start.x );
551 }
552 else
553 {
554 // We use long long here to avoid overflow -- it enforces promotion
555 // The slope of the left-most line is dy/dx. Then we check that the slope from the
556 // left most start to the right most start is the same as well as the slope from the
557 // left most start to right most end.
558 long long dx = leftmost_end.x - leftmost_start.x;
559 long long dy = leftmost_end.y - leftmost_start.y;
560 colinear = ( ( ( other_start.y - leftmost_start.y ) * dx ==
561 ( other_start.x - leftmost_start.x ) * dy ) &&
562 ( ( other_end.y - leftmost_start.y ) * dx ==
563 ( other_end.x - leftmost_start.x ) * dy ) );
564 }
565
566 if( !colinear )
567 return nullptr;
568
569 // We either have a true overlap or colinear touching segments. We always want to merge
570 // the former, but the later only get merged if there no junction at the touch point.
571
572 bool touching = leftmost_end == rightmost_start;
573
574 if( touching && aCheckJunctions && aScreen->IsJunction( leftmost_end ) )
575 return nullptr;
576
577 // Make a new segment that merges the 2 segments
578 leftmost_end = rightmost_end;
579
580 SCH_LINE* ret = new SCH_LINE( *aLine );
581 ret->SetStartPoint( leftmost_start );
582 ret->SetEndPoint( leftmost_end );
583 ret->SetConnectivityDirty( true );
584
585 if( IsSelected() || aLine->IsSelected() )
586 ret->SetSelected();
587
588 return ret;
589}
590
591
593{
594 SCH_LINE* newSegment = static_cast<SCH_LINE*>( Duplicate() );
595
596 newSegment->SetStartPoint( aPoint );
597 newSegment->SetConnectivityDirty( true );
598 SetEndPoint( aPoint );
599
600 return newSegment;
601}
602
603
604void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
605{
606 if( IsConnectable() )
607 {
608 aItemList.emplace_back( IsBus() ? BUS_END : WIRE_END, this, m_start );
609 aItemList.emplace_back( IsBus() ? BUS_END : WIRE_END, this, m_end );
610 }
611}
612
613
614bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
615 const SCH_SHEET_PATH* aPath )
616{
617 if( IsConnectable() )
618 {
619 bool previousStartState = m_startIsDangling;
620 bool previousEndState = m_endIsDangling;
621
623
624 for( DANGLING_END_ITEM item : aItemList )
625 {
626 if( item.GetItem() == this )
627 continue;
628
629 if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
630 || ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
631 {
632 if( m_start == item.GetPosition() )
633 m_startIsDangling = false;
634
635 if( m_end == item.GetPosition() )
636 m_endIsDangling = false;
637
639 break;
640 }
641 }
642
643 // We only use the bus dangling state for automatic line starting, so we don't care if it
644 // has changed or not (and returning true will result in extra work)
645 if( IsBus() )
646 return false;
647
648 return previousStartState != m_startIsDangling || previousEndState != m_endIsDangling;
649 }
650
651 return false;
652}
653
654
656{
657 if( m_layer == LAYER_WIRE || m_layer == LAYER_BUS )
658 return true;
659
660 return false;
661}
662
663
664bool SCH_LINE::CanConnect( const SCH_ITEM* aItem ) const
665{
666 if( m_layer == LAYER_WIRE )
667 {
668 switch( aItem->Type() )
669 {
670 case SCH_JUNCTION_T:
671 case SCH_NO_CONNECT_T:
672 case SCH_LABEL_T:
674 case SCH_HIER_LABEL_T:
677 case SCH_SYMBOL_T:
678 case SCH_SHEET_T:
679 case SCH_SHEET_PIN_T:
680 return true;
681 default:
682 break;
683 }
684 }
685 else if( m_layer == LAYER_BUS )
686 {
687 switch( aItem->Type() )
688 {
689 case SCH_JUNCTION_T:
690 case SCH_LABEL_T:
692 case SCH_HIER_LABEL_T:
695 case SCH_SHEET_T:
696 case SCH_SHEET_PIN_T:
697 return true;
698 default:
699 break;
700 }
701 }
702
703 return aItem->GetLayer() == m_layer;
704}
705
706
707std::vector<VECTOR2I> SCH_LINE::GetConnectionPoints() const
708{
709 return { m_start, m_end };
710}
711
712
714{
715 switch( aItem->Type() )
716 {
717 case SCH_LINE_T:
718 return IsBus() == static_cast<const SCH_LINE*>( aItem )->IsBus();
719
720 default:
721 return true;
722 }
723}
724
725
726void SCH_LINE::GetSelectedPoints( std::vector<VECTOR2I>& aPoints ) const
727{
728 if( m_flags & STARTPOINT )
729 aPoints.push_back( m_start );
730
731 if( m_flags & ENDPOINT )
732 aPoints.push_back( m_end );
733}
734
735
736wxString SCH_LINE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider ) const
737{
738 wxString txtfmt;
739
740 if( m_start.x == m_end.x )
741 {
742 switch( m_layer )
743 {
744 case LAYER_WIRE: txtfmt = _( "Vertical Wire, length %s" ); break;
745 case LAYER_BUS: txtfmt = _( "Vertical Bus, length %s" ); break;
746 default: txtfmt = _( "Vertical Graphic Line, length %s" ); break;
747 }
748 }
749 else if( m_start.y == m_end.y )
750 {
751 switch( m_layer )
752 {
753 case LAYER_WIRE: txtfmt = _( "Horizontal Wire, length %s" ); break;
754 case LAYER_BUS: txtfmt = _( "Horizontal Bus, length %s" ); break;
755 default: txtfmt = _( "Horizontal Graphic Line, length %s" ); break;
756 }
757 }
758 else
759 {
760 switch( m_layer )
761 {
762 case LAYER_WIRE: txtfmt = _( "Wire, length %s" ); break;
763 case LAYER_BUS: txtfmt = _( "Bus, length %s" ); break;
764 default: txtfmt = _( "Graphic Line, length %s" ); break;
765 }
766 }
767
768 return wxString::Format( txtfmt,
769 aUnitsProvider->MessageTextFromValue( EuclideanNorm( m_start - m_end ) ) );
770}
771
772
774{
775 if( m_layer == LAYER_NOTES )
777 else if( m_layer == LAYER_WIRE )
778 return BITMAPS::add_line;
779
780 return BITMAPS::add_bus;
781}
782
783
784bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
785{
786 if( Type() != aItem.Type() )
787 return Type() < aItem.Type();
788
789 const SCH_LINE* line = static_cast<const SCH_LINE*>( &aItem );
790
791 if( GetLayer() != line->GetLayer() )
792 return GetLayer() < line->GetLayer();
793
794 if( GetStartPoint().x != line->GetStartPoint().x )
795 return GetStartPoint().x < line->GetStartPoint().x;
796
797 if( GetStartPoint().y != line->GetStartPoint().y )
798 return GetStartPoint().y < line->GetStartPoint().y;
799
800 if( GetEndPoint().x != line->GetEndPoint().x )
801 return GetEndPoint().x < line->GetEndPoint().x;
802
803 return GetEndPoint().y < line->GetEndPoint().y;
804}
805
806
807bool SCH_LINE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
808{
809 // Performance enhancement for connection-building
810 if( aPosition == m_start || aPosition == m_end )
811 return true;
812
813 if( aAccuracy >= 0 )
814 aAccuracy += GetPenWidth() / 2;
815 else
816 aAccuracy = abs( aAccuracy );
817
818 return TestSegmentHit( aPosition, m_start, m_end, aAccuracy );
819}
820
821
822bool SCH_LINE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
823{
825 return false;
826
827 BOX2I rect = aRect;
828
829 if ( aAccuracy )
830 rect.Inflate( aAccuracy );
831
832 if( aContained )
833 return rect.Contains( m_start ) && rect.Contains( m_end );
834
835 return rect.Intersects( m_start, m_end );
836}
837
838
840{
841 SCH_LINE* item = (SCH_LINE*) aItem;
842
843 std::swap( m_layer, item->m_layer );
844
845 std::swap( m_start, item->m_start );
846 std::swap( m_end, item->m_end );
847 std::swap( m_startIsDangling, item->m_startIsDangling );
848 std::swap( m_endIsDangling, item->m_endIsDangling );
849 std::swap( m_stroke, item->m_stroke );
850}
851
852
853bool SCH_LINE::doIsConnected( const VECTOR2I& aPosition ) const
854{
855 if( m_layer != LAYER_WIRE && m_layer != LAYER_BUS )
856 return false;
857
858 return IsEndPoint( aPosition );
859}
860
861
862void SCH_LINE::Plot( PLOTTER* aPlotter, bool aBackground ) const
863{
864 if( aBackground )
865 return;
866
867 auto* settings = static_cast<KIGFX::SCH_RENDER_SETTINGS*>( aPlotter->RenderSettings() );
868 int penWidth = std::max( GetPenWidth(), settings->GetMinPenWidth() );
870
871 if( color == COLOR4D::UNSPECIFIED )
872 color = settings->GetLayerColor( GetLayer() );
873
874 aPlotter->SetColor( color );
875
876 aPlotter->SetCurrentLineWidth( penWidth );
877 aPlotter->SetDash( penWidth, GetEffectiveLineStyle() );
878
879 aPlotter->MoveTo( m_start );
880 aPlotter->FinishTo( m_end );
881
882 aPlotter->SetDash( penWidth, PLOT_DASH_TYPE::SOLID );
883
884 // Plot attributes to a hypertext menu
885 std::vector<wxString> properties;
886 BOX2I bbox = GetBoundingBox();
887 bbox.Inflate( GetPenWidth() * 3 );
888
889 if( GetLayer() == LAYER_WIRE )
890 {
891 if( SCH_CONNECTION* connection = Connection() )
892 {
893 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
894 _( "Net" ),
895 connection->Name() ) );
896
897 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
898 _( "Resolved netclass" ),
899 GetEffectiveNetClass()->GetName() ) );
900 }
901 }
902 else if( GetLayer() == LAYER_BUS )
903 {
904 if( SCH_CONNECTION* connection = Connection() )
905 {
906 for( std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
907 properties.emplace_back( wxT( "!" ) + member->Name() );
908 }
909
910 }
911
912 if( !properties.empty() )
913 aPlotter->HyperlinkMenu( bbox, properties );
914}
915
916
917void SCH_LINE::SetPosition( const VECTOR2I& aPosition )
918{
919 m_end = m_end - ( m_start - aPosition );
920 m_start = aPosition;
921}
922
923
924void SCH_LINE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
925{
926 wxString msg;
927
928 switch( GetLayer() )
929 {
930 case LAYER_WIRE: msg = _( "Wire" ); break;
931 case LAYER_BUS: msg = _( "Bus" ); break;
932 default: msg = _( "Graphical" ); break;
933 }
934
935 aList.emplace_back( _( "Line Type" ), msg );
936
937 PLOT_DASH_TYPE lineStyle = GetLineStyle();
938
939 if( GetEffectiveLineStyle() != lineStyle )
940 aList.emplace_back( _( "Line Style" ), _( "from netclass" ) );
941 else
942 m_stroke.GetMsgPanelInfo( aFrame, aList, true, false );
943
944 SCH_CONNECTION* conn = nullptr;
945
946 if( !IsConnectivityDirty() && dynamic_cast<SCH_EDIT_FRAME*>( aFrame ) )
947 conn = Connection();
948
949 if( conn )
950 {
951 conn->AppendInfoToMsgPanel( aList );
952
953 if( !conn->IsBus() )
954 {
955 aList.emplace_back( _( "Resolved Netclass" ),
956 UnescapeString( GetEffectiveNetClass()->GetName() ) );
957 }
958 }
959}
960
961
963{
964 return ( GetLayer() == LAYER_NOTES );
965}
966
967
969{
970 return ( GetLayer() == LAYER_WIRE );
971}
972
973
974bool SCH_LINE::IsBus() const
975{
976 return ( GetLayer() == LAYER_BUS );
977}
978
int color
Definition: DXF_plotter.cpp:57
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:111
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
@ add_dashed_line
bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:269
bool Contains(const Vec &aPoint) const
Definition: box2.h:141
BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:506
Helper class used to store the state of schematic items that can be connected to other schematic item...
Definition: sch_item.h:82
The base class for create windows for drawing purpose.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:85
void SetModified()
Definition: eda_item.cpp:64
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:498
bool IsSelected() const
Definition: eda_item.h:106
void SetSelected()
Definition: eda_item.h:115
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:102
double a
Alpha component.
Definition: color4d.h:375
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
int GetDefaultPenWidth() const
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
wxDC * GetPrintDC() const
Store schematic specific render settings.
Definition: sch_painter.h:71
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:69
Base plotter engine class.
Definition: plotter.h:110
virtual void SetDash(int aLineWidth, PLOT_DASH_TYPE aLineStyle)=0
void MoveTo(const VECTOR2I &pos)
Definition: plotter.h:247
void FinishTo(const VECTOR2I &pos)
Definition: plotter.h:257
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:141
virtual void SetCurrentLineWidth(int width, void *aData=nullptr)=0
Set the line width for the next drawing.
virtual void HyperlinkMenu(const BOX2I &aBox, const std::vector< wxString > &aDestURLs)
Create a clickable hyperlink menu with a rectangular click area.
Definition: plotter.h:466
virtual void SetColor(const COLOR4D &color)=0
Holds all the data relating to one schematic.
Definition: schematic.h:61
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:205
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
bool IsBus() const
void AppendInfoToMsgPanel(std::vector< MSG_PANEL_ITEM > &aList) const
Adds information about the connection object to aList.
Schematic editor (Eeschema) main window.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:147
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:112
SCH_ITEM_SET & ConnectedItems(const SCH_SHEET_PATH &aPath)
Retrieve the set of items connected to this item on the given sheet.
Definition: sch_item.cpp:187
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const SCH_SHEET_PATH *aSheet=nullptr) const
Definition: sch_item.cpp:166
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:246
void SetConnectivityDirty(bool aDirty=true)
Definition: sch_item.h:415
bool IsConnectivityDirty() const
Definition: sch_item.h:413
SCH_CONNECTION * Connection(const SCH_SHEET_PATH *aSheet=nullptr) const
Retrieve the connection associated with this object in the given sheet.
Definition: sch_item.cpp:146
SCH_LAYER_ID m_layer
Definition: sch_item.h:491
SCH_ITEM * Duplicate(bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:93
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:40
int GetPenWidth() const override
Definition: sch_line.cpp:323
void Rotate(const VECTOR2I &aCenter) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_line.cpp:407
bool doIsConnected(const VECTOR2I &aPosition) const override
Provide the object specific test to see if it is connected to aPosition.
Definition: sch_line.cpp:853
void GetEndPoints(std::vector< DANGLING_END_ITEM > &aItemList) override
Add the schematic item end points to aItemList if the item has end points.
Definition: sch_line.cpp:604
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:139
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_line.cpp:133
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: sch_line.cpp:773
bool m_startIsDangling
True if start point is not connected.
Definition: sch_line.h:342
bool HitTest(const VECTOR2I &aPosition, int aAccuracy=0) const override
Test if aPosition is inside or on the boundary of this item.
Definition: sch_line.cpp:807
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_line.cpp:917
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
Definition: sch_line.cpp:707
int GetReverseAngleFrom(const VECTOR2I &aPoint) const
Definition: sch_line.cpp:445
double ViewGetLOD(int aLayer, KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: sch_line.cpp:197
SCH_LINE(const VECTOR2I &pos=VECTOR2I(0, 0), int layer=LAYER_NOTES)
Definition: sch_line.cpp:43
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:968
void RotateEnd(const VECTOR2I &aCenter)
Definition: sch_line.cpp:426
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_line.cpp:222
void ViewGetLayers(int aLayers[], int &aCount) const override
Return the layers the item is drawn on (which may be more than its "home" layer)
Definition: sch_line.cpp:187
void SetLineColor(const COLOR4D &aColor)
Definition: sch_line.cpp:244
bool CanConnect(const SCH_ITEM *aItem) const override
Definition: sch_line.cpp:664
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider) const override
Return a user-visible description string of this item.
Definition: sch_line.cpp:736
bool IsParallel(const SCH_LINE *aLine) const
Definition: sch_line.cpp:458
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:316
void RotateStart(const VECTOR2I &aCenter)
Definition: sch_line.cpp:420
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
Definition: sch_line.cpp:397
int GetAngleFrom(const VECTOR2I &aPoint) const
Definition: sch_line.cpp:432
void GetSelectedPoints(std::vector< VECTOR2I > &aPoints) const
Definition: sch_line.cpp:726
COLOR4D m_lastResolvedColor
Definition: sch_line.h:354
void GetMsgPanelInfo(EDA_DRAW_FRAME *aFrame, std::vector< MSG_PANEL_ITEM > &aList) override
Populate aList of MSG_PANEL_ITEM objects with it's internal state for display purposes.
Definition: sch_line.cpp:924
wxString m_operatingPoint
Definition: sch_line.h:356
wxString GetClass() const override
Return the class name.
Definition: sch_line.h:59
VECTOR2I GetEndPoint() const
Definition: sch_line.h:143
VECTOR2I GetStartPoint() const
Definition: sch_line.h:138
bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const override
Return true if this item should propagate connection info to aItem.
Definition: sch_line.cpp:713
SCH_LINE * MergeOverlap(SCH_SCREEN *aScreen, SCH_LINE *aLine, bool aCheckJunctions)
Check line against aLine to see if it overlaps and merge if it does.
Definition: sch_line.cpp:471
VECTOR2I m_start
Line start point.
Definition: sch_line.h:344
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:974
int m_lastResolvedWidth
Definition: sch_line.h:353
VECTOR2I m_end
Line end point.
Definition: sch_line.h:345
PLOT_DASH_TYPE m_lastResolvedLineStyle
Definition: sch_line.h:352
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
Definition: sch_line.cpp:139
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemList, const SCH_SHEET_PATH *aPath=nullptr) override
Test the schematic item to aItemList to check if it's dangling state has changed.
Definition: sch_line.cpp:614
void SetLineStyle(const PLOT_DASH_TYPE aStyle)
Definition: sch_line.cpp:287
PLOT_DASH_TYPE GetLineStyle() const
Definition: sch_line.cpp:294
void MoveEnd(const VECTOR2I &aMoveVector)
Definition: sch_line.cpp:160
STROKE_PARAMS m_stroke
Line stroke properties.
Definition: sch_line.h:347
bool m_endIsDangling
True if end point is not connected.
Definition: sch_line.h:343
void SwapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
Definition: sch_line.cpp:839
bool IsConnectable() const override
Definition: sch_line.cpp:655
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
Definition: sch_line.cpp:387
bool operator<(const SCH_ITEM &aItem) const override
Definition: sch_line.cpp:784
void Print(const RENDER_SETTINGS *aSettings, const VECTOR2I &aOffset) override
Print a schematic item.
Definition: sch_line.cpp:357
wxString GetNetname(const SCH_SHEET_PATH &aSheet)
This function travel though all the connected wire segments to look for connected labels.
Definition: sch_line.cpp:93
bool IsEndPoint(const VECTOR2I &aPoint) const
Definition: sch_line.h:92
void Plot(PLOTTER *aPlotter, bool aBackground) const override
Plot the schematic item to aPlotter.
Definition: sch_line.cpp:862
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
Definition: sch_line.cpp:962
COLOR4D GetLineColor() const
Returns COLOR4D::UNSPECIFIED if a custom color hasn't been set for this line.
Definition: sch_line.cpp:268
void MoveStart(const VECTOR2I &aMoveVector)
Definition: sch_line.cpp:150
double GetLength() const
Definition: sch_line.cpp:238
PLOT_DASH_TYPE GetEffectiveLineStyle() const
Definition: sch_line.cpp:303
SCH_LINE * BreakAt(const VECTOR2I &aPoint)
Break this segment into two at the specified point.
Definition: sch_line.cpp:592
wxString FindWireSegmentNetNameRecursive(SCH_LINE *line, std::list< const SCH_LINE * > &checkedLines, const SCH_SHEET_PATH &aSheet) const
Recursively called function to travel through the connected wires and find a connected net name label...
Definition: sch_line.cpp:101
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:144
bool IsJunction(const VECTOR2I &aPosition) const
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:458
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
int GetWidth() const
Definition: stroke_params.h:98
void SetWidth(int aWidth)
Definition: stroke_params.h:99
void SetColor(const KIGFX::COLOR4D &aColor)
void GetMsgPanelInfo(UNITS_PROVIDER *aUnitsProvider, std::vector< MSG_PANEL_ITEM > &aList, bool aIncludeStyle=true, bool aIncludeWidth=true)
static void Stroke(const SHAPE *aShape, PLOT_DASH_TYPE aLineStyle, int aWidth, const KIGFX::RENDER_SETTINGS *aRenderSettings, std::function< void(const VECTOR2I &a, const VECTOR2I &b)> aStroker)
KIGFX::COLOR4D GetColor() const
PLOT_DASH_TYPE GetPlotStyle() const
void SetPlotStyle(PLOT_DASH_TYPE aPlotStyle)
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
A lower-precision version of StringFromValue().
#define DEFAULT_BUS_WIDTH_MILS
The default noconnect size in mils.
#define DEFAULT_WIRE_WIDTH_MILS
The default bus width in mils. (can be changed in preference menu)
#define DEFAULT_LINE_WIDTH_MILS
The default wire width in mils. (can be changed in preference menu)
#define _(s)
static constexpr EDA_ANGLE & ANGLE_90
Definition: eda_angle.h:431
#define STRUCT_DELETED
flag indication structures to be erased
#define ENDPOINT
ends. (Used to support dragging.)
#define SKIP_STRUCT
flag indicating that the structure should be ignored
#define STARTPOINT
When a line is selected, these flags indicate which.
void GRLine(wxDC *DC, int x1, int y1, int x2, int y2, int width, const COLOR4D &Color, wxPenStyle aStyle)
Definition: gr_basic.cpp:171
@ LAYER_DANGLING
Definition: layer_ids.h:368
@ LAYER_WIRE
Definition: layer_ids.h:344
@ LAYER_NOTES
Definition: layer_ids.h:358
@ LAYER_BUS
Definition: layer_ids.h:345
@ LAYER_SELECTION_SHADOWS
Definition: layer_ids.h:381
@ LAYER_OP_VOLTAGES
Definition: layer_ids.h:387
void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:40
wxString GetText(EDA_UNITS aUnits, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE)
Get the units string for a given units type.
Definition: eda_units.cpp:101
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:418
Plot settings, and plotting engines (PostScript, Gerber, HPGL and DXF)
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
@ BUS_END
Definition: sch_item.h:66
@ PIN_END
Definition: sch_item.h:68
@ BUS_ENTRY_END
Definition: sch_item.h:70
@ WIRE_END
Definition: sch_item.h:65
wxString UnescapeString(const wxString &aSource)
PLOT_DASH_TYPE
Dashed line types.
Definition: stroke_params.h:48
constexpr int MilsToIU(int mils) const
Definition: base_units.h:94
constexpr int mmToIU(double mm) const
Definition: base_units.h:89
bool TestSegmentHit(const VECTOR2I &aRefPoint, const VECTOR2I &aStart, const VECTOR2I &aEnd, int aDist)
Test if aRefPoint is with aDistance on the line defined by aStart and aEnd.
Definition: trigo.cpp:129
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Definition: trigo.cpp:183
double GetLineLength(const VECTOR2I &aPointA, const VECTOR2I &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:188
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
@ SCH_LINE_T
Definition: typeinfo.h:146
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:143
@ SCH_SYMBOL_T
Definition: typeinfo.h:156
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:154
@ SCH_LABEL_T
Definition: typeinfo.h:151
@ SCH_SHEET_T
Definition: typeinfo.h:158
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:153
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:157
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:144
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:152
@ SCH_JUNCTION_T
Definition: typeinfo.h:142
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< int > VECTOR2I
Definition: vector2d.h:590