KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 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#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 <sch_plotter.h>
32#include <sch_line.h>
33#include <sch_edit_frame.h>
35#include <connection_graph.h>
38#include <trigo.h>
39#include <board_item.h>
40#include <api/api_enums.h>
41#include <api/api_utils.h>
42#include <api/schematic/schematic_types.pb.h>
43#include <properties/property.h>
44
45
46SCH_LINE::SCH_LINE( const VECTOR2I& pos, int layer ) :
47 SCH_ITEM( nullptr, SCH_LINE_T )
48{
49 m_start = pos;
50 m_end = pos;
51 m_stroke.SetWidth( 0 );
52 m_stroke.SetLineStyle( LINE_STYLE::DEFAULT );
53 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
54
55 switch( layer )
56 {
57 default: m_layer = LAYER_NOTES; break;
58 case LAYER_WIRE: m_layer = LAYER_WIRE; break;
59 case LAYER_BUS: m_layer = LAYER_BUS; break;
60 }
61
62 if( layer == LAYER_NOTES )
64 else
66
67 if( layer == LAYER_WIRE )
69 else if( layer == LAYER_BUS )
71 else
73
74 m_lastResolvedLineStyle = LINE_STYLE::SOLID;
75 m_lastResolvedColor = COLOR4D::UNSPECIFIED;
76}
77
78
80 SCH_ITEM( aLine )
81{
82 m_start = aLine.m_start;
83 m_end = aLine.m_end;
84 m_stroke = aLine.m_stroke;
87
91
93
94 // Don't apply groups to cloned lines. We have too many areas where we clone them
95 // temporarily, then modify/split/join them in the line movement routines after the
96 // segments are committed. Rely on the commit framework to add the lines to the
97 // entered group as appropriate.
98 m_group = nullptr;
99}
100
101
102void SCH_LINE::Serialize( google::protobuf::Any &aContainer ) const
103{
104 kiapi::schematic::types::Line line;
105
106 line.mutable_id()->set_value( m_Uuid.AsStdString() );
107 kiapi::common::PackVector2( *line.mutable_start(), GetStartPoint() );
108 kiapi::common::PackVector2( *line.mutable_end(), GetEndPoint() );
109 line.set_layer(
110 ToProtoEnum<SCH_LAYER_ID, kiapi::schematic::types::SchematicLayer>( GetLayer() ) );
111
112 aContainer.PackFrom( line );
113}
114
115
116bool SCH_LINE::Deserialize( const google::protobuf::Any &aContainer )
117{
118 kiapi::schematic::types::Line line;
119
120 if( !aContainer.UnpackTo( &line ) )
121 return false;
122
123 const_cast<KIID&>( m_Uuid ) = KIID( line.id().value() );
126 SCH_LAYER_ID layer =
127 FromProtoEnum<SCH_LAYER_ID, kiapi::schematic::types::SchematicLayer>( line.layer() );
128
129 switch( layer )
130 {
131 case LAYER_WIRE:
132 case LAYER_BUS:
133 case LAYER_NOTES:
134 SetLayer( layer );
135 break;
136
137 default:
138 break;
139 }
140
141 return true;
142}
143
144
146{
147 switch( GetLayer() )
148 {
149 case LAYER_WIRE: return _( "Wire" );
150 case LAYER_BUS: return _( "Bus" );
151 default: return _( "Graphic Line" );
152 }
153}
154
155
157{
158 return new SCH_LINE( *this );
159}
160
161
162void SCH_LINE::Move( const VECTOR2I& aOffset )
163{
164 m_start += aOffset;
165 m_end += aOffset;
166}
167
168
169void SCH_LINE::MoveStart( const VECTOR2I& aOffset )
170{
171 m_start += aOffset;
172}
173
174
175void SCH_LINE::MoveEnd( const VECTOR2I& aOffset )
176{
177 m_end += aOffset;
178}
179
180
181#if defined(DEBUG)
182
183void SCH_LINE::Show( int nestLevel, std::ostream& os ) const
184{
185 NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
186 << " layer=\"" << m_layer << '"'
187 << " startIsDangling=\"" << m_startIsDangling
188 << '"' << " endIsDangling=\""
189 << m_endIsDangling << '"' << ">"
190 << " <start" << m_start << "/>"
191 << " <end" << m_end << "/>" << "</"
192 << GetClass().Lower().mb_str() << ">\n";
193}
194
195#endif
196
197
198std::vector<int> SCH_LINE::ViewGetLayers() const
199{
202}
203
204
205double SCH_LINE::ViewGetLOD( int aLayer, const KIGFX::VIEW* aView ) const
206{
207 if( aLayer == LAYER_OP_VOLTAGES )
208 {
209 if( m_start == m_end )
210 return LOD_HIDE;
211
212 const int height = std::abs( m_end.y - m_start.y );
213
214 // Operating points will be shown only if zoom is appropriate
215 if( height > 0 )
216 return lodScaleForThreshold( aView, height, schIUScale.mmToIU( 5 ) );
217
218 const int width = std::abs( m_end.x - m_start.x );
219 return lodScaleForThreshold( aView, width, schIUScale.mmToIU( 15 ) );
220 }
221
222 // Other layers are always drawn.
223 return LOD_SHOW;
224}
225
226
228{
229 int width = GetPenWidth() / 2;
230
231 int xmin = std::min( m_start.x, m_end.x ) - width;
232 int ymin = std::min( m_start.y, m_end.y ) - width;
233
234 int xmax = std::max( m_start.x, m_end.x ) + width + 1;
235 int ymax = std::max( m_start.y, m_end.y ) + width + 1;
236
237 BOX2I ret( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin, ymax - ymin ) );
238
239 return ret;
240}
241
242
244{
245 return m_start.Distance( m_end );
246}
247
248
249void SCH_LINE::SetLineColor( const COLOR4D& aColor )
250{
251 m_stroke.SetColor( aColor );
253}
254
255
256void SCH_LINE::SetLineColor( const double r, const double g, const double b, const double a )
257{
258 COLOR4D newColor(r, g, b, a);
259
260 if( newColor == COLOR4D::UNSPECIFIED )
261 {
262 m_stroke.SetColor( COLOR4D::UNSPECIFIED );
263 }
264 else
265 {
266 // Eeschema does not allow alpha channel in colors
267 newColor.a = 1.0;
268 m_stroke.SetColor( newColor );
269 }
270}
271
272
274{
275 if( m_stroke.GetColor() != COLOR4D::UNSPECIFIED )
277 else if( !IsConnectable() )
278 m_lastResolvedColor = COLOR4D::UNSPECIFIED;
279 else if( !IsConnectivityDirty() )
280 m_lastResolvedColor = GetEffectiveNetClass()->GetSchematicColor();
281
282 return m_lastResolvedColor;
283}
284
285
287{
288 m_stroke.SetLineStyle( aStyle );
290}
291
292
294{
295 if( IsGraphicLine() && m_stroke.GetLineStyle() == LINE_STYLE::DEFAULT )
296 return LINE_STYLE::SOLID;
297 else
298 return m_stroke.GetLineStyle();
299}
300
301
303{
304 if( m_stroke.GetLineStyle() != LINE_STYLE::DEFAULT )
306 else if( !IsConnectable() )
307 m_lastResolvedLineStyle = LINE_STYLE::SOLID;
308 else if( !IsConnectivityDirty() )
310
312}
313
314
315void SCH_LINE::SetLineWidth( const int aSize )
316{
317 m_stroke.SetWidth( aSize );
319}
320
321
323{
324 SCHEMATIC* schematic = Schematic();
325
326 switch ( m_layer )
327 {
328 default:
329 if( m_stroke.GetWidth() > 0 )
330 return m_stroke.GetWidth();
331
332 if( schematic )
333 return schematic->Settings().m_DefaultLineWidth;
334
336
337 case LAYER_WIRE:
338 if( m_stroke.GetWidth() > 0 )
340 else if( !IsConnectivityDirty() )
341 m_lastResolvedWidth = GetEffectiveNetClass()->GetWireWidth();
342
343 return m_lastResolvedWidth;
344
345 case LAYER_BUS:
346 if( m_stroke.GetWidth() > 0 )
348 else if( !IsConnectivityDirty() )
349 m_lastResolvedWidth = GetEffectiveNetClass()->GetBusWidth();
350
351 return m_lastResolvedWidth;
352 }
353}
354
355
356void SCH_LINE::MirrorVertically( int aCenter )
357{
358 if( m_flags & STARTPOINT )
359 MIRROR( m_start.y, aCenter );
360
361 if( m_flags & ENDPOINT )
362 MIRROR( m_end.y, aCenter );
363}
364
365
367{
368 if( m_flags & STARTPOINT )
369 MIRROR( m_start.x, aCenter );
370
371 if( m_flags & ENDPOINT )
372 MIRROR( m_end.x, aCenter );
373}
374
375
376void SCH_LINE::Rotate( const VECTOR2I& aCenter, bool aRotateCCW )
377{
378 if( m_flags & STARTPOINT )
379 RotatePoint( m_start, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
380
381 if( m_flags & ENDPOINT )
382 RotatePoint( m_end, aCenter, aRotateCCW ? ANGLE_90 : ANGLE_270 );
383}
384
385
386int SCH_LINE::GetAngleFrom( const VECTOR2I& aPoint ) const
387{
388 VECTOR2I vec;
389
390 if( aPoint == m_start )
391 vec = m_end - aPoint;
392 else
393 vec = m_start - aPoint;
394
395 return KiROUND( EDA_ANGLE( vec ).AsDegrees() );
396}
397
398
399int SCH_LINE::GetReverseAngleFrom( const VECTOR2I& aPoint ) const
400{
401 VECTOR2I vec;
402
403 if( aPoint == m_end )
404 vec = m_start - aPoint;
405 else
406 vec = m_end - aPoint;
407
408 return KiROUND( EDA_ANGLE( vec ).AsDegrees() );
409}
410
411
412bool SCH_LINE::IsParallel( const SCH_LINE* aLine ) const
413{
414 wxCHECK_MSG( aLine != nullptr && aLine->Type() == SCH_LINE_T, false,
415 wxT( "Cannot test line segment for overlap." ) );
416
417 VECTOR2I firstSeg = m_end - m_start;
418 VECTOR2I secondSeg = aLine->m_end - aLine->m_start;
419
420 // Use long long here to avoid overflow in calculations
421 return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x );
422}
423
424
425SCH_LINE* SCH_LINE::MergeOverlap( SCH_SCREEN* aScreen, SCH_LINE* aLine, bool aCheckJunctions )
426{
427 auto less =
428 []( const VECTOR2I& lhs, const VECTOR2I& rhs ) -> bool
429 {
430 if( lhs.x == rhs.x )
431 return lhs.y < rhs.y;
432
433 return lhs.x < rhs.x;
434 };
435
436 wxCHECK_MSG( aLine != nullptr && aLine->Type() == SCH_LINE_T, nullptr,
437 wxT( "Cannot test line segment for overlap." ) );
438
439 if( this == aLine || GetLayer() != aLine->GetLayer() )
440 return nullptr;
441
442 VECTOR2I leftmost_start = aLine->m_start;
443 VECTOR2I leftmost_end = aLine->m_end;
444
445 VECTOR2I rightmost_start = m_start;
446 VECTOR2I rightmost_end = m_end;
447
448 // We place the start to the left and below the end of both lines
449 if( leftmost_start != std::min( { leftmost_start, leftmost_end }, less ) )
450 std::swap( leftmost_start, leftmost_end );
451 if( rightmost_start != std::min( { rightmost_start, rightmost_end }, less ) )
452 std::swap( rightmost_start, rightmost_end );
453
454 // - leftmost is the line that starts farthest to the left
455 // - other is the line that is _not_ leftmost
456 // - rightmost is the line that ends farthest to the right. This may or may not be 'other'
457 // as the second line may be completely covered by the first.
458 if( less( rightmost_start, leftmost_start ) )
459 {
460 std::swap( leftmost_start, rightmost_start );
461 std::swap( leftmost_end, rightmost_end );
462 }
463
464 VECTOR2I other_start = rightmost_start;
465 VECTOR2I other_end = rightmost_end;
466
467 if( less( rightmost_end, leftmost_end ) )
468 {
469 rightmost_start = leftmost_start;
470 rightmost_end = leftmost_end;
471 }
472
473 // If we end one before the beginning of the other, no overlap is possible
474 if( less( leftmost_end, other_start ) )
475 {
476 return nullptr;
477 }
478
479 // Search for a common end:
480 if( ( leftmost_start == other_start ) && ( leftmost_end == other_end ) ) // Trivial case
481 {
482 SCH_LINE* ret = new SCH_LINE( *aLine );
483 ret->SetStartPoint( leftmost_start );
484 ret->SetEndPoint( leftmost_end );
485 ret->SetConnectivityDirty( true );
486
487 if( IsSelected() || aLine->IsSelected() )
488 ret->SetSelected();
489
490 return ret;
491 }
492
493 bool colinear = false;
494
495 /* Test alignment: */
496 if( ( leftmost_start.y == leftmost_end.y ) &&
497 ( other_start.y == other_end.y ) ) // Horizontal segment
498 {
499 colinear = ( leftmost_start.y == other_start.y );
500 }
501 else if( ( leftmost_start.x == leftmost_end.x ) &&
502 ( other_start.x == other_end.x ) ) // Vertical segment
503 {
504 colinear = ( leftmost_start.x == other_start.x );
505 }
506 else
507 {
508 // We use long long here to avoid overflow -- it enforces promotion
509 // The slope of the left-most line is dy/dx. Then we check that the slope from the
510 // left most start to the right most start is the same as well as the slope from the
511 // left most start to right most end.
512 long long dx = leftmost_end.x - leftmost_start.x;
513 long long dy = leftmost_end.y - leftmost_start.y;
514 colinear = ( ( ( other_start.y - leftmost_start.y ) * dx ==
515 ( other_start.x - leftmost_start.x ) * dy ) &&
516 ( ( other_end.y - leftmost_start.y ) * dx ==
517 ( other_end.x - leftmost_start.x ) * dy ) );
518 }
519
520 if( !colinear )
521 return nullptr;
522
523 // We either have a true overlap or colinear touching segments. We always want to merge
524 // the former, but the later only get merged if there no junction at the touch point.
525
526 bool touching = leftmost_end == rightmost_start;
527
528 if( touching && aCheckJunctions && aScreen->IsJunction( leftmost_end ) )
529 return nullptr;
530
531 // Make a new segment that merges the 2 segments
532 leftmost_end = rightmost_end;
533
534 SCH_LINE* ret = new SCH_LINE( *aLine );
535 ret->SetStartPoint( leftmost_start );
536 ret->SetEndPoint( leftmost_end );
537 ret->SetConnectivityDirty( true );
538
539 if( IsSelected() || aLine->IsSelected() )
540 ret->SetSelected();
541
542 return ret;
543}
544
545
547{
548 SCH_LINE* newSegment = static_cast<SCH_LINE*>( Duplicate( true /* addToParentGroup */, aCommit ) );
549
550 newSegment->SetStartPoint( aPoint );
551 newSegment->SetConnectivityDirty( true );
552 SetEndPoint( aPoint );
553
554 return newSegment;
555}
556
557
559{
560 SCH_LINE* newSegment = static_cast<SCH_LINE*>( Duplicate( false /* addToParentGroup */, nullptr ) );
561
562 newSegment->SetStartPoint( aPoint );
563 newSegment->SetConnectivityDirty( true );
564 SetEndPoint( aPoint );
565
566 return newSegment;
567}
568
569
570void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
571{
572 if( IsConnectable() )
573 {
574 aItemList.emplace_back( IsBus() ? BUS_END : WIRE_END, this, m_start );
575 aItemList.emplace_back( IsBus() ? BUS_END : WIRE_END, this, m_end );
576 }
577}
578
579
580bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
581 std::vector<DANGLING_END_ITEM>& aItemListByPos,
582 const SCH_SHEET_PATH* aPath )
583{
584 if( !IsConnectable() )
585 return false;
586
587 bool previousStartState = m_startIsDangling;
588 bool previousEndState = m_endIsDangling;
589
591
592 for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, m_start );
593 it < aItemListByPos.end() && it->GetPosition() == m_start; it++ )
594 {
595 DANGLING_END_ITEM& item = *it;
596
597 if( item.GetItem() == this )
598 continue;
599
600 if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
601 || ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
602 {
603 m_startIsDangling = false;
604 break;
605 }
606 }
607
608 for( auto it = DANGLING_END_ITEM_HELPER::get_lower_pos( aItemListByPos, m_end );
609 it < aItemListByPos.end() && it->GetPosition() == m_end; it++ )
610 {
611 DANGLING_END_ITEM& item = *it;
612
613 if( item.GetItem() == this )
614 continue;
615
616 if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
617 || ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
618 {
619 m_endIsDangling = false;
620 break;
621 }
622 }
623
624 // We only use the bus dangling state for automatic line starting, so we don't care if it
625 // has changed or not (and returning true will result in extra work)
626 if( IsBus() )
627 return false;
628
629 return previousStartState != m_startIsDangling || previousEndState != m_endIsDangling;
630}
631
632
634{
635 if( m_layer == LAYER_WIRE || m_layer == LAYER_BUS )
636 return true;
637
638 return false;
639}
640
641
642bool SCH_LINE::CanConnect( const SCH_ITEM* aItem ) const
643{
644 switch( aItem->Type() )
645 {
646 case SCH_NO_CONNECT_T:
647 case SCH_SYMBOL_T:
648 return IsWire();
649
650 case SCH_JUNCTION_T:
651 case SCH_LABEL_T:
653 case SCH_HIER_LABEL_T:
656 case SCH_SHEET_T:
657 case SCH_SHEET_PIN_T:
658 return IsWire() || IsBus();
659
660 default:
661 return m_layer == aItem->GetLayer();
662 }
663}
664
665
667 const SCH_SHEET_PATH* aInstance ) const
668{
669 // Do not compare to ourself.
670 if( aItem == this || !IsConnectable() )
671 return false;
672
673 const SCH_LINE* line = dynamic_cast<const SCH_LINE*>( aItem );
674
675 // Don't compare against a different SCH_ITEM.
676 wxCHECK( line, false );
677
678 if( GetStartPoint() != line->GetStartPoint() )
679 return true;
680
681 return GetEndPoint() != line->GetEndPoint();
682}
683
684
685std::vector<VECTOR2I> SCH_LINE::GetConnectionPoints() const
686{
687 return { m_start, m_end };
688}
689
690
692{
693 switch( aItem->Type() )
694 {
695 case SCH_LINE_T:
696 return IsBus() == static_cast<const SCH_LINE*>( aItem )->IsBus();
697
698 default:
699 return true;
700 }
701}
702
703
704void SCH_LINE::GetSelectedPoints( std::vector<VECTOR2I>& aPoints ) const
705{
706 if( m_flags & STARTPOINT )
707 aPoints.push_back( m_start );
708
709 if( m_flags & ENDPOINT )
710 aPoints.push_back( m_end );
711}
712
713
714wxString SCH_LINE::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const
715{
716 wxString txtfmt;
717
718 if( m_start.x == m_end.x )
719 {
720 switch( m_layer )
721 {
722 case LAYER_WIRE: txtfmt = _( "Vertical Wire, length %s" ); break;
723 case LAYER_BUS: txtfmt = _( "Vertical Bus, length %s" ); break;
724 default: txtfmt = _( "Vertical Graphic Line, length %s" ); break;
725 }
726 }
727 else if( m_start.y == m_end.y )
728 {
729 switch( m_layer )
730 {
731 case LAYER_WIRE: txtfmt = _( "Horizontal Wire, length %s" ); break;
732 case LAYER_BUS: txtfmt = _( "Horizontal Bus, length %s" ); break;
733 default: txtfmt = _( "Horizontal Graphic Line, length %s" ); break;
734 }
735 }
736 else
737 {
738 switch( m_layer )
739 {
740 case LAYER_WIRE: txtfmt = _( "Wire, length %s" ); break;
741 case LAYER_BUS: txtfmt = _( "Bus, length %s" ); break;
742 default: txtfmt = _( "Graphic Line, length %s" ); break;
743 }
744 }
745
746 return wxString::Format( txtfmt,
747 aUnitsProvider->MessageTextFromValue( m_start.Distance( m_end ) ) );
748}
749
750
752{
753 if( m_layer == LAYER_NOTES )
754 return BITMAPS::add_dashed_line;
755 else if( m_layer == LAYER_WIRE )
756 return BITMAPS::add_line;
757
758 return BITMAPS::add_bus;
759}
760
761
762bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
763{
764 if( Type() != aItem.Type() )
765 return Type() < aItem.Type();
766
767 const SCH_LINE* line = static_cast<const SCH_LINE*>( &aItem );
768
769 if( GetLayer() != line->GetLayer() )
770 return GetLayer() < line->GetLayer();
771
772 if( GetStartPoint().x != line->GetStartPoint().x )
773 return GetStartPoint().x < line->GetStartPoint().x;
774
775 if( GetStartPoint().y != line->GetStartPoint().y )
776 return GetStartPoint().y < line->GetStartPoint().y;
777
778 if( GetEndPoint().x != line->GetEndPoint().x )
779 return GetEndPoint().x < line->GetEndPoint().x;
780
781 return GetEndPoint().y < line->GetEndPoint().y;
782}
783
784
785bool SCH_LINE::HitTest( const VECTOR2I& aPosition, int aAccuracy ) const
786{
787 // Performance enhancement for connection-building
788 if( aPosition == m_start || aPosition == m_end )
789 return true;
790
791 if( aAccuracy >= 0 )
792 aAccuracy += GetPenWidth() / 2;
793 else
794 aAccuracy = abs( aAccuracy );
795
796 return TestSegmentHit( aPosition, m_start, m_end, aAccuracy );
797}
798
799
800bool SCH_LINE::HitTest( const BOX2I& aRect, bool aContained, int aAccuracy ) const
801{
803 return false;
804
805 BOX2I rect = aRect;
806
807 if ( aAccuracy )
808 rect.Inflate( aAccuracy );
809
810 if( aContained )
811 return rect.Contains( m_start ) && rect.Contains( m_end );
812
813 return rect.Intersects( m_start, m_end );
814}
815
816
818{
819 SCH_LINE* item = (SCH_LINE*) aItem;
820
821 std::swap( m_layer, item->m_layer );
822
823 std::swap( m_start, item->m_start );
824 std::swap( m_end, item->m_end );
825 std::swap( m_startIsDangling, item->m_startIsDangling );
826 std::swap( m_endIsDangling, item->m_endIsDangling );
827 std::swap( m_stroke, item->m_stroke );
828}
829
830
831bool SCH_LINE::doIsConnected( const VECTOR2I& aPosition ) const
832{
833 if( m_layer != LAYER_WIRE && m_layer != LAYER_BUS )
834 return false;
835
836 return IsEndPoint( aPosition );
837}
838
839
840void SCH_LINE::Plot( PLOTTER* aPlotter, bool aBackground, const SCH_PLOT_OPTS& aPlotOpts,
841 int aUnit, int aBodyStyle, const VECTOR2I& aOffset, bool aDimmed )
842{
843 if( aBackground )
844 return;
845
846 SCH_RENDER_SETTINGS* renderSettings = getRenderSettings( aPlotter );
847 int penWidth = GetEffectivePenWidth( renderSettings );
849
850 if( color == COLOR4D::UNSPECIFIED )
851 color = renderSettings->GetLayerColor( GetLayer() );
852
853 aPlotter->SetColor( color );
854
855 aPlotter->SetCurrentLineWidth( penWidth );
856 aPlotter->SetDash( penWidth, GetEffectiveLineStyle() );
857
858 aPlotter->MoveTo( m_start );
859 aPlotter->FinishTo( m_end );
860
861 aPlotter->SetDash( penWidth, LINE_STYLE::SOLID );
862
863 // Plot attributes to a hypertext menu
864 std::vector<wxString> properties;
865 BOX2I bbox = GetBoundingBox();
866 bbox.Inflate( penWidth * 3 );
867
868 if( aPlotOpts.m_PDFPropertyPopups )
869 {
870 if( GetLayer() == LAYER_WIRE )
871 {
872 if( SCH_CONNECTION* connection = Connection() )
873 {
874 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
875 _( "Net" ),
876 connection->Name() ) );
877
878 properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
879 _( "Resolved netclass" ),
880 GetEffectiveNetClass()->GetHumanReadableName() ) );
881 }
882 }
883 else if( GetLayer() == LAYER_BUS )
884 {
885 if( SCH_CONNECTION* connection = Connection() )
886 {
887 for( const std::shared_ptr<SCH_CONNECTION>& member : connection->Members() )
888 properties.emplace_back( wxT( "!" ) + member->Name() );
889 }
890 }
891
892 if( !properties.empty() )
893 aPlotter->HyperlinkMenu( bbox, properties );
894 }
895}
896
897
898void SCH_LINE::SetPosition( const VECTOR2I& aPosition )
899{
900 m_end = m_end - ( m_start - aPosition );
901 m_start = aPosition;
902}
903
904
905void SCH_LINE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
906{
907 wxString msg;
908
909 switch( GetLayer() )
910 {
911 case LAYER_WIRE: msg = _( "Wire" ); break;
912 case LAYER_BUS: msg = _( "Bus" ); break;
913 default: msg = _( "Graphical" ); break;
914 }
915
916 aList.emplace_back( _( "Line Type" ), msg );
917
918 LINE_STYLE lineStyle = GetStroke().GetLineStyle();
919
920 if( GetEffectiveLineStyle() != lineStyle )
921 aList.emplace_back( _( "Line Style" ), _( "from netclass" ) );
922 else
923 m_stroke.GetMsgPanelInfo( aFrame, aList, true, false );
924
925 SCH_CONNECTION* conn = nullptr;
926
927 if( !IsConnectivityDirty() && dynamic_cast<SCH_EDIT_FRAME*>( aFrame ) )
928 conn = Connection();
929
930 if( conn )
931 {
932 conn->AppendInfoToMsgPanel( aList );
933
934 if( !conn->IsBus() )
935 {
936 aList.emplace_back( _( "Resolved Netclass" ),
937 UnescapeString( GetEffectiveNetClass()->GetHumanReadableName() ) );
938 }
939 }
940}
941
942
944{
945 return ( GetLayer() == LAYER_NOTES );
946}
947
948
950{
951 return ( GetLayer() == LAYER_WIRE );
952}
953
954
955bool SCH_LINE::IsBus() const
956{
957 return ( GetLayer() == LAYER_BUS );
958}
959
960
961bool SCH_LINE::operator==( const SCH_ITEM& aOther ) const
962{
963 if( Type() != aOther.Type() )
964 return false;
965
966 const SCH_LINE& other = static_cast<const SCH_LINE&>( aOther );
967
968 if( GetLayer() != other.GetLayer() )
969 return false;
970
971 if( m_start != other.m_start )
972 return false;
973
974 if( m_end != other.m_end )
975 return false;
976
977 if( m_stroke.GetWidth() != other.m_stroke.GetWidth() )
978 return false;
979
980 if( m_stroke.GetColor() != other.m_stroke.GetColor() )
981 return false;
982
983 if( m_stroke.GetLineStyle() != other.m_stroke.GetLineStyle() )
984 return false;
985
986 return true;
987}
988
989
990double SCH_LINE::Similarity( const SCH_ITEM& aOther ) const
991{
992 if( m_Uuid == aOther.m_Uuid )
993 return 1.0;
994
995 if( Type() != aOther.Type() )
996 return 0.0;
997
998 const SCH_LINE& other = static_cast<const SCH_LINE&>( aOther );
999
1000 if( GetLayer() != other.GetLayer() )
1001 return 0.0;
1002
1003 double similarity = 1.0;
1004
1005 if( m_start != other.m_start )
1006 similarity *= 0.9;
1007
1008 if( m_end != other.m_end )
1009 similarity *= 0.9;
1010
1011 if( m_stroke.GetWidth() != other.m_stroke.GetWidth() )
1012 similarity *= 0.9;
1013
1014 if( m_stroke.GetColor() != other.m_stroke.GetColor() )
1015 similarity *= 0.9;
1016
1017 if( m_stroke.GetLineStyle() != other.m_stroke.GetLineStyle() )
1018 similarity *= 0.9;
1019
1020 return similarity;
1021}
1022
1023
1024bool SCH_LINE::ShouldHopOver( const SCH_LINE* aLine ) const
1025{
1026 // try to find if this should hop over aLine. Horizontal wires have preference for hop.
1027 bool isMeVertical = ( m_end.x == m_start.x );
1028 bool isCandidateVertical = ( aLine->GetEndPoint().x == aLine->GetStartPoint().x );
1029
1030 // Vertical vs. Horizontal: Horizontal should hop
1031 if( isMeVertical && !isCandidateVertical )
1032 return false;
1033
1034 if( isCandidateVertical && !isMeVertical )
1035 return true;
1036
1037 // Both this and aLine have a slope. Try to find the best candidate
1038 double slopeMe = ( m_end.y - m_start.y ) / (double) ( m_end.x - m_start.x );
1039 double slopeCandidate = ( aLine->GetEndPoint().y - aLine->GetStartPoint().y )
1040 / (double) ( aLine->GetEndPoint().x - aLine->GetStartPoint().x );
1041
1042 if( fabs( slopeMe ) == fabs( slopeCandidate ) ) // Can easily happen with 45 deg wires
1043 return slopeMe < slopeCandidate; // signs are certainly different
1044
1045 return fabs( slopeMe ) < fabs( slopeCandidate ); // The shallower line should hop
1046}
1047
1048
1049std::vector<VECTOR3I> SCH_LINE::BuildWireWithHopShape( const SCH_SCREEN* aScreen,
1050 double aArcRadius ) const
1051{
1052 // Note: Points are VECTOR3D, with Z coord used as flag
1053 // for segments: start point and end point have the Z coord = 0
1054 // for arcs: start point middle point and end point have the Z coord = 1
1055
1056 std::vector<VECTOR3I> wire_shape; // List of coordinates:
1057 // 2 points for a segment, 3 points for an arc
1058
1059 if( !IsWire() )
1060 {
1061 wire_shape.emplace_back( GetStartPoint().x,GetStartPoint().y, 0 );
1062 wire_shape.emplace_back( GetEndPoint().x, GetEndPoint().y, 0 );
1063 return wire_shape;
1064 }
1065
1066 std::vector<SCH_LINE*> existingWires; // wires to test (candidates)
1067 std::vector<VECTOR2I> intersections;
1068
1069 for( SCH_ITEM* item : aScreen->Items().Overlapping( SCH_LINE_T, GetBoundingBox() ) )
1070 {
1071 SCH_LINE* line = static_cast<SCH_LINE*>( item );
1072
1073 if( line->IsWire() )
1074 existingWires.push_back( line );
1075 }
1076
1077 VECTOR2I currentLineStartPoint = GetStartPoint();
1078 VECTOR2I currentLineEndPoint = GetEndPoint();
1079
1080 for( SCH_LINE* existingLine : existingWires )
1081 {
1082 VECTOR2I extLineStartPoint = existingLine->GetStartPoint();
1083 VECTOR2I extLineEndPoint = existingLine->GetEndPoint();
1084
1085 if( extLineStartPoint == currentLineStartPoint && extLineEndPoint == currentLineEndPoint )
1086 continue;
1087
1088 if( !ShouldHopOver( existingLine ) )
1089 continue;
1090
1091 SEG currentSegment = SEG( currentLineStartPoint, currentLineEndPoint );
1092 SEG existingSegment = SEG( extLineStartPoint, extLineEndPoint );
1093
1094 if( OPT_VECTOR2I intersect = currentSegment.Intersect( existingSegment, true, false ) )
1095 {
1096 if( IsEndPoint( *intersect ) || existingLine->IsEndPoint( *intersect ) )
1097 continue;
1098
1099 // Ensure intersecting point is not yet entered. it can be already just entered
1100 // if more than two wires are intersecting at the same point,
1101 // creating bad hop over shapes for the current wire
1102 if( intersections.size() == 0 || intersections.back() != *intersect )
1103 intersections.push_back( *intersect );
1104 }
1105 }
1106
1107 if( intersections.empty() )
1108 {
1109 wire_shape.emplace_back( currentLineStartPoint.x, currentLineStartPoint.y, 0 );
1110 wire_shape.emplace_back( currentLineEndPoint.x, currentLineEndPoint.y, 0 );
1111 }
1112 else
1113 {
1114 auto getDistance =
1115 []( const VECTOR2I& a, const VECTOR2I& b ) -> double
1116 {
1117 return std::sqrt( std::pow( a.x - b.x, 2 ) + std::pow( a.y - b.y, 2 ) );
1118 };
1119
1120 std::sort( intersections.begin(), intersections.end(),
1121 [&]( const VECTOR2I& a, const VECTOR2I& b )
1122 {
1123 return getDistance( GetStartPoint(), a ) < getDistance( GetStartPoint(), b );
1124 } );
1125
1126 VECTOR2I currentStart = GetStartPoint();
1127 double arcRadius = aArcRadius;
1128
1129 for( const VECTOR2I& hopMid : intersections )
1130 {
1131 // Calculate the angle of the line from start point to end point in radians
1132 double lineAngle = std::atan2( GetEndPoint().y - GetStartPoint().y,
1133 GetEndPoint().x - GetStartPoint().x );
1134
1135 // Convert the angle from radians to degrees
1136 double lineAngleDeg = lineAngle * ( 180.0f / M_PI );
1137
1138 // Normalize the angle to be between 0 and 360 degrees
1139 if( lineAngleDeg < 0 )
1140 lineAngleDeg += 360;
1141
1142 double startAngle = lineAngleDeg;
1143 double endAngle = startAngle + 180.0f;
1144
1145 // Adjust the end angle if it exceeds 360 degrees
1146 if( endAngle >= 360.0 )
1147 endAngle -= 360.0;
1148
1149 // Convert start and end angles from degrees to radians
1150 double startAngleRad = startAngle * ( M_PI / 180.0f );
1151 double endAngleRad = endAngle * ( M_PI / 180.0f );
1152
1153 VECTOR2I arcMidPoint = {
1154 hopMid.x + static_cast<int>( arcRadius
1155 * cos( ( startAngleRad + endAngleRad ) / 2.0f ) ),
1156 hopMid.y - static_cast<int>( arcRadius
1157 * sin( ( startAngleRad + endAngleRad ) / 2.0f ) )
1158 };
1159
1160 VECTOR2I beforeHop = hopMid - VECTOR2I( arcRadius * std::cos( lineAngle ),
1161 arcRadius * std::sin( lineAngle ) );
1162 VECTOR2I afterHop = hopMid + VECTOR2I( arcRadius * std::cos( lineAngle ),
1163 arcRadius * std::sin( lineAngle ) );
1164
1165 // Draw the line from the current start point to the before-hop point
1166 wire_shape.emplace_back( currentStart.x, currentStart.y, 0 );
1167 wire_shape.emplace_back( beforeHop.x, beforeHop.y, 0 );
1168
1169 // Create an arc object
1170 SHAPE_ARC arc( beforeHop, arcMidPoint, afterHop, 0 );
1171 wire_shape.emplace_back( beforeHop.x, beforeHop.y, 1 );
1172 wire_shape.emplace_back( arcMidPoint.x, arcMidPoint.y, 1 );
1173 wire_shape.emplace_back( afterHop.x, afterHop.y, 1 );
1174
1175 currentStart = afterHop;
1176 }
1177
1178 // Draw the final line from the current start point to the end point of the original line
1179 wire_shape.emplace_back( currentStart. x,currentStart.y, 0 );
1180 wire_shape.emplace_back( GetEndPoint().x, GetEndPoint().y, 0 );
1181 }
1182
1183 return wire_shape;
1184}
1185
1186
1187static struct SCH_LINE_DESC
1188{
1190 {
1192
1193 if( lineStyleEnum.Choices().GetCount() == 0 )
1194 {
1195 lineStyleEnum.Map( LINE_STYLE::SOLID, _HKI( "Solid" ) )
1196 .Map( LINE_STYLE::DASH, _HKI( "Dashed" ) )
1197 .Map( LINE_STYLE::DOT, _HKI( "Dotted" ) )
1198 .Map( LINE_STYLE::DASHDOT, _HKI( "Dash-Dot" ) )
1199 .Map( LINE_STYLE::DASHDOTDOT, _HKI( "Dash-Dot-Dot" ) );
1200 }
1201
1203
1204 if( wireLineStyleEnum.Choices().GetCount() == 0 )
1205 {
1206 wireLineStyleEnum.Map( WIRE_STYLE::DEFAULT, _HKI( "Default" ) )
1207 .Map( WIRE_STYLE::SOLID, _HKI( "Solid" ) )
1208 .Map( WIRE_STYLE::DASH, _HKI( "Dashed" ) )
1209 .Map( WIRE_STYLE::DOT, _HKI( "Dotted" ) )
1210 .Map( WIRE_STYLE::DASHDOT, _HKI( "Dash-Dot" ) )
1211 .Map( WIRE_STYLE::DASHDOTDOT, _HKI( "Dash-Dot-Dot" ) );
1212 }
1213
1217
1218 auto isGraphicLine =
1219 []( INSPECTABLE* aItem ) -> bool
1220 {
1221 if( SCH_LINE* line = dynamic_cast<SCH_LINE*>( aItem ) )
1222 return line->IsGraphicLine();
1223
1224 return false;
1225 };
1226
1227 auto isWireOrBus =
1228 []( INSPECTABLE* aItem ) -> bool
1229 {
1230 if( SCH_LINE* line = dynamic_cast<SCH_LINE*>( aItem ) )
1231 return line->IsWire() || line->IsBus();
1232
1233 return false;
1234 };
1235
1236 propMgr.AddProperty( new PROPERTY_ENUM<SCH_LINE, LINE_STYLE>( _HKI( "Line Style" ),
1238 .SetAvailableFunc( isGraphicLine );
1239
1240 propMgr.AddProperty( new PROPERTY_ENUM<SCH_LINE, WIRE_STYLE>( _HKI( "Line Style" ),
1242 .SetAvailableFunc( isWireOrBus );
1243
1244 propMgr.AddProperty( new PROPERTY<SCH_LINE, int>( _HKI( "Line Width" ),
1245 &SCH_LINE::SetLineWidth, &SCH_LINE::GetLineWidth, PROPERTY_DISPLAY::PT_SIZE ) );
1246
1247 propMgr.AddProperty( new PROPERTY<SCH_LINE, COLOR4D>( _HKI( "Color" ),
1249 }
1251
int color
Definition: DXF_plotter.cpp:63
constexpr EDA_IU_SCALE schIUScale
Definition: base_units.h:114
BITMAPS
A list of all bitmap identifiers.
Definition: bitmaps_list.h:33
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition: box2.h:990
constexpr BOX2< Vec > & Inflate(coord_type dx, coord_type dy)
Inflates the rectangle horizontally by dx and vertically by dy.
Definition: box2.h:558
constexpr bool Contains(const Vec &aPoint) const
Definition: box2.h:168
constexpr bool Intersects(const BOX2< Vec > &aRect) const
Definition: box2.h:311
static std::vector< DANGLING_END_ITEM >::iterator get_lower_pos(std::vector< DANGLING_END_ITEM > &aItemListByPos, const VECTOR2I &aPos)
Definition: sch_item.cpp:795
Helper class used to store the state of schematic items that can be connected to other schematic item...
Definition: sch_item.h:97
DANGLING_END_T GetType() const
Definition: sch_item.h:133
EDA_ITEM * GetItem() const
Definition: sch_item.h:131
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:98
const KIID m_Uuid
Definition: eda_item.h:516
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:110
EDA_ITEM_FLAGS m_flags
Definition: eda_item.h:527
EDA_GROUP * m_group
The group this item belongs to, if any. No ownership implied.
Definition: eda_item.h:529
bool IsSelected() const
Definition: eda_item.h:127
void SetSelected()
Definition: eda_item.h:134
EE_TYPE Overlapping(const BOX2I &aRect) const
Definition: sch_rtree.h:246
ENUM_MAP & Map(T aValue, const wxString &aName)
Definition: property.h:703
static ENUM_MAP< T > & Instance()
Definition: property.h:697
wxPGChoices & Choices()
Definition: property.h:746
Class that other classes need to inherit from, in order to be inspectable.
Definition: inspectable.h:37
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:104
double a
Alpha component.
Definition: color4d.h:395
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
static double lodScaleForThreshold(const KIGFX::VIEW *aView, int aWhatIu, int aThresholdIu)
Get the scale at which aWhatIu would be drawn at the same size as aThresholdIu on screen.
Definition: view_item.cpp:39
static constexpr double LOD_HIDE
Return this constant from ViewGetLOD() to hide the item unconditionally.
Definition: view_item.h:180
static constexpr double LOD_SHOW
Return this constant from ViewGetLOD() to show the item unconditionally.
Definition: view_item.h:185
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition: view.h:66
Definition: kiid.h:49
std::string AsStdString() const
Definition: kiid.cpp:252
Base plotter engine class.
Definition: plotter.h:121
void MoveTo(const VECTOR2I &pos)
Definition: plotter.h:261
virtual void SetDash(int aLineWidth, LINE_STYLE aLineStyle)=0
void FinishTo(const VECTOR2I &pos)
Definition: plotter.h:271
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:471
virtual void SetColor(const COLOR4D &color)=0
PROPERTY_BASE & SetAvailableFunc(std::function< bool(INSPECTABLE *)> aFunc)
Set a callback function to determine whether an object provides this property.
Definition: property.h:258
Provide class metadata.Helper macro to map type hashes to names.
Definition: property_mgr.h:74
void InheritsAfter(TYPE_ID aDerived, TYPE_ID aBase)
Declare an inheritance relationship between types.
static PROPERTY_MANAGER & Instance()
Definition: property_mgr.h:76
PROPERTY_BASE & AddProperty(PROPERTY_BASE *aProperty, const wxString &aGroup=wxEmptyString)
Register a property.
Holds all the data relating to one schematic.
Definition: schematic.h:88
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:356
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:168
SCH_ITEM * Duplicate(bool addToParentGroup, SCH_COMMIT *aCommit=nullptr, bool doClone=false) const
Routine to create a new copy of given item.
Definition: sch_item.cpp:137
SCH_RENDER_SETTINGS * getRenderSettings(PLOTTER *aPlotter) const
Definition: sch_item.h:693
SCHEMATIC * Schematic() const
Search the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:246
std::shared_ptr< NETCLASS > GetEffectiveNetClass(const SCH_SHEET_PATH *aSheet=nullptr) const
Definition: sch_item.cpp:381
void SetLayer(SCH_LAYER_ID aLayer)
Definition: sch_item.h:314
SCH_LAYER_ID GetLayer() const
Return the layer this item is on.
Definition: sch_item.h:313
void SetConnectivityDirty(bool aDirty=true)
Definition: sch_item.h:561
bool IsConnectivityDirty() const
Definition: sch_item.h:559
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:352
int GetEffectivePenWidth(const SCH_RENDER_SETTINGS *aSettings) const
Definition: sch_item.cpp:626
SCH_LAYER_ID m_layer
Definition: sch_item.h:744
Segment description base class to describe items which have 2 end points (track, wire,...
Definition: sch_line.h:42
int GetPenWidth() const override
Definition: sch_line.cpp:322
bool doIsConnected(const VECTOR2I &aPosition) const override
Provide the object specific test to see if it is connected to aPosition.
Definition: sch_line.cpp:831
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:570
void SetStartPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:140
EDA_ITEM * Clone() const override
Create a duplicate of this item with linked list members set to NULL.
Definition: sch_line.cpp:156
BITMAPS GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: sch_line.cpp:751
bool UpdateDanglingState(std::vector< DANGLING_END_ITEM > &aItemListByType, std::vector< DANGLING_END_ITEM > &aItemListByPos, 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:580
bool m_startIsDangling
True if start point is not connected.
Definition: sch_line.h:376
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:785
void SetPosition(const VECTOR2I &aPosition) override
Definition: sch_line.cpp:898
std::vector< VECTOR3I > BuildWireWithHopShape(const SCH_SCREEN *aScreen, double aArcRadius) const
For wires only: build the list of points to draw the shape using segments and 180 deg arcs Points are...
Definition: sch_line.cpp:1049
SCH_LINE * NonGroupAware_BreakAt(const VECTOR2I &aPoint)
This version should only be used when importing files.
Definition: sch_line.cpp:558
std::vector< VECTOR2I > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
Definition: sch_line.cpp:685
int GetReverseAngleFrom(const VECTOR2I &aPoint) const
Definition: sch_line.cpp:399
SCH_LINE(const VECTOR2I &pos=VECTOR2I(0, 0), int layer=LAYER_NOTES)
Definition: sch_line.cpp:46
bool IsWire() const
Return true if the line is a wire.
Definition: sch_line.cpp:949
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: sch_line.cpp:227
void SetWireStyle(const WIRE_STYLE aStyle)
Definition: sch_line.h:178
void SetLineColor(const COLOR4D &aColor)
Definition: sch_line.cpp:249
bool CanConnect(const SCH_ITEM *aItem) const override
Definition: sch_line.cpp:642
bool IsParallel(const SCH_LINE *aLine) const
Definition: sch_line.cpp:412
void SetLineWidth(const int aSize)
Definition: sch_line.cpp:315
bool ShouldHopOver(const SCH_LINE *aLine) const
For wires only:
Definition: sch_line.cpp:1024
void MirrorHorizontally(int aCenter) override
Mirror item horizontally about aCenter.
Definition: sch_line.cpp:366
virtual STROKE_PARAMS GetStroke() const override
Definition: sch_line.h:193
int GetAngleFrom(const VECTOR2I &aPoint) const
Definition: sch_line.cpp:386
void GetSelectedPoints(std::vector< VECTOR2I > &aPoints) const
Definition: sch_line.cpp:704
COLOR4D m_lastResolvedColor
Definition: sch_line.h:388
LINE_STYLE GetEffectiveLineStyle() const
Definition: sch_line.cpp:302
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:905
void Plot(PLOTTER *aPlotter, bool aBackground, const SCH_PLOT_OPTS &aPlotOpts, int aUnit, int aBodyStyle, const VECTOR2I &aOffset, bool aDimmed) override
Plot the item to aPlotter.
Definition: sch_line.cpp:840
wxString m_operatingPoint
Definition: sch_line.h:390
wxString GetClass() const override
Return the class name.
Definition: sch_line.h:64
void Rotate(const VECTOR2I &aCenter, bool aRotateCCW) override
Rotate the item around aCenter 90 degrees in the clockwise direction.
Definition: sch_line.cpp:376
VECTOR2I GetEndPoint() const
Definition: sch_line.h:144
VECTOR2I GetStartPoint() const
Definition: sch_line.h:139
bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const override
Return true if this item should propagate connection info to aItem.
Definition: sch_line.cpp:691
LINE_STYLE m_lastResolvedLineStyle
Definition: sch_line.h:386
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:425
VECTOR2I m_start
Line start point.
Definition: sch_line.h:378
bool IsBus() const
Return true if the line is a bus.
Definition: sch_line.cpp:955
int m_lastResolvedWidth
Definition: sch_line.h:387
bool HasConnectivityChanges(const SCH_ITEM *aItem, const SCH_SHEET_PATH *aInstance=nullptr) const override
Check if aItem has connectivity changes against this object.
Definition: sch_line.cpp:666
void Serialize(google::protobuf::Any &aContainer) const override
Serializes this object to the given Any message.
Definition: sch_line.cpp:102
void SetLineStyle(const LINE_STYLE aStyle)
Definition: sch_line.cpp:286
VECTOR2I m_end
Line end point.
Definition: sch_line.h:379
void Move(const VECTOR2I &aMoveVector) override
Move the item by aMoveVector to a new position.
Definition: sch_line.cpp:162
LINE_STYLE GetLineStyle() const
Definition: sch_line.cpp:293
void MoveEnd(const VECTOR2I &aMoveVector)
Definition: sch_line.cpp:175
STROKE_PARAMS m_stroke
Line stroke properties.
Definition: sch_line.h:381
SCH_LINE * BreakAt(SCH_COMMIT *aCommit, const VECTOR2I &aPoint)
Break this segment into two at the specified point.
Definition: sch_line.cpp:546
bool m_endIsDangling
True if end point is not connected.
Definition: sch_line.h:377
bool IsConnectable() const override
Definition: sch_line.cpp:633
wxString GetFriendlyName() const override
Definition: sch_line.cpp:145
double ViewGetLOD(int aLayer, const KIGFX::VIEW *aView) const override
Return the level of detail (LOD) of the item.
Definition: sch_line.cpp:205
void MirrorVertically(int aCenter) override
Mirror item vertically about aCenter.
Definition: sch_line.cpp:356
bool operator==(const SCH_ITEM &aOther) const override
Definition: sch_line.cpp:961
bool operator<(const SCH_ITEM &aItem) const override
Definition: sch_line.cpp:762
WIRE_STYLE GetWireStyle() const
Definition: sch_line.h:179
wxString GetItemDescription(UNITS_PROVIDER *aUnitsProvider, bool aFull) const override
Return a user-visible description string of this item.
Definition: sch_line.cpp:714
bool IsEndPoint(const VECTOR2I &aPoint) const override
Test if aPt is an end point of this schematic object.
Definition: sch_line.h:91
bool IsGraphicLine() const
Return if the line is a graphic (non electrical line)
Definition: sch_line.cpp:943
int GetLineWidth() const
Definition: sch_line.h:190
COLOR4D GetLineColor() const
Return #COLOR4D::UNSPECIFIED if a custom color hasn't been set for this line.
Definition: sch_line.cpp:273
std::vector< int > ViewGetLayers() const override
Return the layers the item is drawn on (which may be more than its "home" layer)
Definition: sch_line.cpp:198
void MoveStart(const VECTOR2I &aMoveVector)
Definition: sch_line.cpp:169
bool Deserialize(const google::protobuf::Any &aContainer) override
Deserializes the given protobuf message into this object.
Definition: sch_line.cpp:116
double GetLength() const
Definition: sch_line.cpp:243
void SetEndPoint(const VECTOR2I &aPosition)
Definition: sch_line.h:145
double Similarity(const SCH_ITEM &aOther) const override
Return a measure of how likely the other object is to represent the same object.
Definition: sch_line.cpp:990
void swapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
Definition: sch_line.cpp:817
EE_RTREE & Items()
Get the full RTree, usually for iterating.
Definition: sch_screen.h:117
bool IsJunction(const VECTOR2I &aPosition) const
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:474
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
Definition: seg.h:42
OPT_VECTOR2I Intersect(const SEG &aSeg, bool aIgnoreEndpoints=false, bool aLines=false) const
Compute intersection point of segment (this) with segment aSeg.
Definition: seg.cpp:439
int GetWidth() const
void SetLineStyle(LINE_STYLE aLineStyle)
void SetWidth(int aWidth)
void SetColor(const KIGFX::COLOR4D &aColor)
void GetMsgPanelInfo(UNITS_PROVIDER *aUnitsProvider, std::vector< MSG_PANEL_ITEM > &aList, bool aIncludeStyle=true, bool aIncludeWidth=true)
LINE_STYLE GetLineStyle() const
KIGFX::COLOR4D GetColor() const
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
double Distance(const VECTOR2< extended_type > &aVector) const
Compute the distance between two vectors.
Definition: vector2d.h:561
#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 _HKI(x)
#define _(s)
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:413
static constexpr EDA_ANGLE ANGLE_270
Definition: eda_angle.h:416
#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.
SCH_LAYER_ID
Eeschema drawing layers.
Definition: layer_ids.h:439
@ LAYER_DANGLING
Definition: layer_ids.h:467
@ LAYER_WIRE
Definition: layer_ids.h:442
@ LAYER_NOTES
Definition: layer_ids.h:457
@ LAYER_NET_COLOR_HIGHLIGHT
Definition: layer_ids.h:483
@ LAYER_BUS
Definition: layer_ids.h:443
@ LAYER_SELECTION_SHADOWS
Definition: layer_ids.h:484
@ LAYER_OP_VOLTAGES
Definition: layer_ids.h:490
constexpr void MIRROR(T &aPoint, const T &aMirrorRef)
Updates aPoint with the mirror of aPoint relative to the aMirrorRef.
Definition: mirror.h:45
KICOMMON_API VECTOR2I UnpackVector2(const types::Vector2 &aInput)
Definition: api_utils.cpp:85
KICOMMON_API void PackVector2(types::Vector2 &aOutput, const VECTOR2I &aInput)
Definition: api_utils.cpp:78
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:400
static bool intersect(const SEGMENT_WITH_NORMALS &aSeg, const SFVEC2F &aStart, const SFVEC2F &aEnd)
Definition: polygon_2d.cpp:273
#define TYPE_HASH(x)
Definition: property.h:72
#define IMPLEMENT_ENUM_TO_WXANY(type)
Definition: property.h:797
#define REGISTER_TYPE(x)
Definition: property_mgr.h:351
@ BUS_END
Definition: sch_item.h:81
@ PIN_END
Definition: sch_item.h:83
@ BUS_ENTRY_END
Definition: sch_item.h:85
@ WIRE_END
Definition: sch_item.h:80
static struct SCH_LINE_DESC _SCH_LINE_DESC
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
wxString UnescapeString(const wxString &aSource)
LINE_STYLE
Dashed line types.
Definition: stroke_params.h:46
WIRE_STYLE
Definition: stroke_params.h:68
constexpr int MilsToIU(int mils) const
Definition: base_units.h:97
constexpr int mmToIU(double mm) const
Definition: base_units.h:92
bool m_PDFPropertyPopups
Definition: sch_plotter.h:64
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:175
void RotatePoint(int *pX, int *pY, const EDA_ANGLE &aAngle)
Calculate the new point of coord coord pX, pY, for a rotation center 0, 0.
Definition: trigo.cpp:229
@ SCH_LINE_T
Definition: typeinfo.h:164
@ SCH_NO_CONNECT_T
Definition: typeinfo.h:161
@ SCH_SYMBOL_T
Definition: typeinfo.h:173
@ SCH_DIRECTIVE_LABEL_T
Definition: typeinfo.h:172
@ SCH_LABEL_T
Definition: typeinfo.h:168
@ SCH_SHEET_T
Definition: typeinfo.h:176
@ SCH_HIER_LABEL_T
Definition: typeinfo.h:170
@ SCH_SHEET_PIN_T
Definition: typeinfo.h:175
@ SCH_BUS_WIRE_ENTRY_T
Definition: typeinfo.h:162
@ SCH_GLOBAL_LABEL_T
Definition: typeinfo.h:169
@ SCH_JUNCTION_T
Definition: typeinfo.h:160
VECTOR2< int32_t > VECTOR2I
Definition: vector2d.h:695