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