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  // When we allow off grid items, the
451  // else if should become a plain if to allow
452  // rotation around the center of the line
453  if( m_flags & STARTPOINT )
454  RotatePoint( &m_start, aCenter, 900 );
455  else if( m_flags & ENDPOINT )
456  RotatePoint( &m_end, aCenter, 900 );
457 }
458 
459 
460 void SCH_LINE::RotateStart( const wxPoint& aCenter )
461 {
462  RotatePoint( &m_start, aCenter, 900 );
463 }
464 
465 
466 void SCH_LINE::RotateEnd( const wxPoint& aCenter )
467 {
468  RotatePoint( &m_end, aCenter, 900 );
469 }
470 
471 
472 int SCH_LINE::GetAngleFrom( const wxPoint& aPoint ) const
473 {
474  wxPoint vec;
475 
476  if( aPoint == m_start )
477  vec = m_end - aPoint;
478  else
479  vec = m_start - aPoint;
480 
481  return KiROUND( ArcTangente( vec.y, vec.x ) );
482 }
483 
484 
485 int SCH_LINE::GetReverseAngleFrom( const wxPoint& aPoint ) const
486 {
487  wxPoint vec;
488 
489  if( aPoint == m_end )
490  vec = m_start - aPoint;
491  else
492  vec = m_end - aPoint;
493 
494  return KiROUND( ArcTangente( vec.y, vec.x ) );
495 }
496 
497 
498 bool SCH_LINE::IsParallel( const SCH_LINE* aLine ) const
499 {
500  wxCHECK_MSG( aLine != nullptr && aLine->Type() == SCH_LINE_T, false,
501  wxT( "Cannot test line segment for overlap." ) );
502 
503  wxPoint firstSeg = m_end - m_start;
504  wxPoint secondSeg = aLine->m_end - aLine->m_start;
505 
506  // Use long long here to avoid overflow in calculations
507  return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x );
508 }
509 
510 
511 SCH_LINE* SCH_LINE::MergeOverlap( SCH_SCREEN* aScreen, SCH_LINE* aLine, bool aCheckJunctions )
512 {
513  auto less =
514  []( const wxPoint& lhs, const wxPoint& rhs ) -> bool
515  {
516  if( lhs.x == rhs.x )
517  return lhs.y < rhs.y;
518 
519  return lhs.x < rhs.x;
520  };
521 
522  wxCHECK_MSG( aLine != nullptr && aLine->Type() == SCH_LINE_T, nullptr,
523  wxT( "Cannot test line segment for overlap." ) );
524 
525  if( this == aLine || GetLayer() != aLine->GetLayer() )
526  return nullptr;
527 
528  wxPoint leftmost_start = aLine->m_start;
529  wxPoint leftmost_end = aLine->m_end;
530 
531  wxPoint rightmost_start = m_start;
532  wxPoint rightmost_end = m_end;
533 
534  // We place the start to the left and below the end of both lines
535  if( leftmost_start != std::min( { leftmost_start, leftmost_end }, less ) )
536  std::swap( leftmost_start, leftmost_end );
537  if( rightmost_start != std::min( { rightmost_start, rightmost_end }, less ) )
538  std::swap( rightmost_start, rightmost_end );
539 
540  // - leftmost is the line that starts farthest to the left
541  // - other is the line that is _not_ leftmost
542  // - rightmost is the line that ends farthest to the right. This may or may not be 'other'
543  // as the second line may be completely covered by the first.
544  if( less( rightmost_start, leftmost_start ) )
545  {
546  std::swap( leftmost_start, rightmost_start );
547  std::swap( leftmost_end, rightmost_end );
548  }
549 
550  wxPoint other_start = rightmost_start;
551  wxPoint other_end = rightmost_end;
552 
553  if( less( rightmost_end, leftmost_end ) )
554  {
555  rightmost_start = leftmost_start;
556  rightmost_end = leftmost_end;
557  }
558 
559  // If we end one before the beginning of the other, no overlap is possible
560  if( less( leftmost_end, other_start ) )
561  {
562  return nullptr;
563  }
564 
565  // Search for a common end:
566  if( ( leftmost_start == other_start ) && ( leftmost_end == other_end ) ) // Trivial case
567  {
568  SCH_LINE* ret = new SCH_LINE( *aLine );
569  ret->SetStartPoint( leftmost_start );
570  ret->SetEndPoint( leftmost_end );
571  ret->SetConnectivityDirty( true );
572 
573  if( IsSelected() || aLine->IsSelected() )
574  ret->SetSelected();
575 
576  return ret;
577  }
578 
579  bool colinear = false;
580 
581  /* Test alignment: */
582  if( ( leftmost_start.y == leftmost_end.y ) &&
583  ( other_start.y == other_end.y ) ) // Horizontal segment
584  {
585  colinear = ( leftmost_start.y == other_start.y );
586  }
587  else if( ( leftmost_start.x == leftmost_end.x ) &&
588  ( other_start.x == other_end.x ) ) // Vertical segment
589  {
590  colinear = ( leftmost_start.x == other_start.x );
591  }
592  else
593  {
594  // We use long long here to avoid overflow -- it enforces promotion
595  // The slope of the left-most line is dy/dx. Then we check that the slope from the
596  // left most start to the right most start is the same as well as the slope from the
597  // left most start to right most end.
598  long long dx = leftmost_end.x - leftmost_start.x;
599  long long dy = leftmost_end.y - leftmost_start.y;
600  colinear = ( ( ( other_start.y - leftmost_start.y ) * dx ==
601  ( other_start.x - leftmost_start.x ) * dy ) &&
602  ( ( other_end.y - leftmost_start.y ) * dx ==
603  ( other_end.x - leftmost_start.x ) * dy ) );
604  }
605 
606  if( !colinear )
607  return nullptr;
608 
609  // We either have a true overlap or colinear touching segments. We always want to merge
610  // the former, but the later only get merged if there no junction at the touch point.
611 
612  bool touching = leftmost_end == rightmost_start;
613 
614  if( touching && aCheckJunctions && aScreen->IsJunction( leftmost_end ) )
615  return nullptr;
616 
617  // Make a new segment that merges the 2 segments
618  leftmost_end = rightmost_end;
619 
620  SCH_LINE* ret = new SCH_LINE( *aLine );
621  ret->SetStartPoint( leftmost_start );
622  ret->SetEndPoint( leftmost_end );
623  ret->SetConnectivityDirty( true );
624 
625  if( IsSelected() || aLine->IsSelected() )
626  ret->SetSelected();
627 
628  return ret;
629 }
630 
631 
632 void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
633 {
634  if( IsConnectable() )
635  {
636  aItemList.emplace_back( IsBus() ? BUS_END : WIRE_END, this, m_start );
637  aItemList.emplace_back( IsBus() ? BUS_END : WIRE_END, this, m_end );
638  }
639 }
640 
641 
642 bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
643  const SCH_SHEET_PATH* aPath )
644 {
645  if( IsConnectable() )
646  {
647  bool previousStartState = m_startIsDangling;
648  bool previousEndState = m_endIsDangling;
649 
651 
652  for( DANGLING_END_ITEM item : aItemList )
653  {
654  if( item.GetItem() == this )
655  continue;
656 
657  if( ( IsWire() && item.GetType() != BUS_END && item.GetType() != BUS_ENTRY_END )
658  || ( IsBus() && item.GetType() != WIRE_END && item.GetType() != PIN_END ) )
659  {
660  if( m_start == item.GetPosition() )
661  m_startIsDangling = false;
662 
663  if( m_end == item.GetPosition() )
664  m_endIsDangling = false;
665 
667  break;
668  }
669  }
670 
671  // We only use the bus dangling state for automatic line starting, so we don't care if it
672  // has changed or not (and returning true will result in extra work)
673  if( IsBus() )
674  return false;
675 
676  return previousStartState != m_startIsDangling || previousEndState != m_endIsDangling;
677  }
678 
679  return false;
680 }
681 
682 
684 {
685  if( m_layer == LAYER_WIRE || m_layer == LAYER_BUS )
686  return true;
687 
688  return false;
689 }
690 
691 
692 bool SCH_LINE::CanConnect( const SCH_ITEM* aItem ) const
693 {
694  if( m_layer == LAYER_WIRE )
695  {
696  switch( aItem->Type() )
697  {
698  case SCH_JUNCTION_T:
699  case SCH_NO_CONNECT_T:
700  case SCH_LABEL_T:
701  case SCH_GLOBAL_LABEL_T:
702  case SCH_HIER_LABEL_T:
704  case SCH_SYMBOL_T:
705  case SCH_SHEET_T:
706  case SCH_SHEET_PIN_T:
707  return true;
708  default:
709  break;
710  }
711  }
712  else if( m_layer == LAYER_BUS )
713  {
714  switch( aItem->Type() )
715  {
716  case SCH_JUNCTION_T:
717  case SCH_LABEL_T:
718  case SCH_GLOBAL_LABEL_T:
719  case SCH_HIER_LABEL_T:
721  case SCH_SHEET_T:
722  case SCH_SHEET_PIN_T:
723  return true;
724  default:
725  break;
726  }
727  }
728 
729  return aItem->GetLayer() == m_layer;
730 }
731 
732 
733 std::vector<wxPoint> SCH_LINE::GetConnectionPoints() const
734 {
735  return { m_start, m_end };
736 }
737 
738 
739 bool SCH_LINE::ConnectionPropagatesTo( const EDA_ITEM* aItem ) const
740 {
741  switch( aItem->Type() )
742  {
743  case SCH_LINE_T:
744  return IsBus() == static_cast<const SCH_LINE*>( aItem )->IsBus();
745 
746  default:
747  return true;
748  }
749 }
750 
751 
752 void SCH_LINE::GetSelectedPoints( std::vector< wxPoint >& aPoints ) const
753 {
754  if( m_flags & STARTPOINT )
755  aPoints.push_back( m_start );
756 
757  if( m_flags & ENDPOINT )
758  aPoints.push_back( m_end );
759 }
760 
761 
762 wxString SCH_LINE::GetSelectMenuText( EDA_UNITS aUnits ) const
763 {
764  wxString txtfmt, orient;
765 
766  if( m_start.x == m_end.x )
767  {
768  switch( m_layer )
769  {
770  case LAYER_WIRE: txtfmt = _( "Vertical Wire, length %s" ); break;
771  case LAYER_BUS: txtfmt = _( "Vertical Bus, length %s" ); break;
772  default: txtfmt = _( "Vertical Graphic Line, length %s" ); break;
773  }
774  }
775  else if( m_start.y == m_end.y )
776  {
777  switch( m_layer )
778  {
779  case LAYER_WIRE: txtfmt = _( "Horizontal Wire, length %s" ); break;
780  case LAYER_BUS: txtfmt = _( "Horizontal Bus, length %s" ); break;
781  default: txtfmt = _( "Horizontal Graphic Line, length %s" ); break;
782  }
783  }
784  else
785  {
786  switch( m_layer )
787  {
788  case LAYER_WIRE: txtfmt = _( "Wire, length %s" ); break;
789  case LAYER_BUS: txtfmt = _( "Bus, length %s" ); break;
790  default: txtfmt = _( "Graphic Line, length %s" ); break;
791  }
792  }
793 
794  return wxString::Format( txtfmt,
796 }
797 
798 
800 {
801  if( m_layer == LAYER_NOTES )
803  else if( m_layer == LAYER_WIRE )
804  return BITMAPS::add_line;
805 
806  return BITMAPS::add_bus;
807 }
808 
809 
810 bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
811 {
812  if( Type() != aItem.Type() )
813  return Type() < aItem.Type();
814 
815  const SCH_LINE* line = static_cast<const SCH_LINE*>( &aItem );
816 
817  if( GetLayer() != line->GetLayer() )
818  return GetLayer() < line->GetLayer();
819 
820  if( GetStartPoint().x != line->GetStartPoint().x )
821  return GetStartPoint().x < line->GetStartPoint().x;
822 
823  if( GetStartPoint().y != line->GetStartPoint().y )
824  return GetStartPoint().y < line->GetStartPoint().y;
825 
826  if( GetEndPoint().x != line->GetEndPoint().x )
827  return GetEndPoint().x < line->GetEndPoint().x;
828 
829  return GetEndPoint().y < line->GetEndPoint().y;
830 }
831 
832 
833 bool SCH_LINE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
834 {
835  // Performance enhancement for connection-building
836  if( aPosition == m_start || aPosition == m_end )
837  return true;
838 
839  if( aAccuracy >= 0 )
840  aAccuracy += GetPenWidth() / 2;
841  else
842  aAccuracy = abs( aAccuracy );
843 
844  if( TestSegmentHit( aPosition, m_start, m_end, aAccuracy ) )
845  return true;
846 
847  aAccuracy += Mils2iu( DANGLING_SYMBOL_SIZE );
848 
849  return ( EuclideanNorm( aPosition - m_start ) < aAccuracy
850  || EuclideanNorm( aPosition - m_end ) < aAccuracy );
851 }
852 
853 
854 bool SCH_LINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
855 {
856  if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) )
857  return false;
858 
859  EDA_RECT rect = aRect;
860 
861  if ( aAccuracy )
862  rect.Inflate( aAccuracy );
863 
864  if( aContained )
865  return rect.Contains( m_start ) && rect.Contains( m_end );
866 
867  return rect.Intersects( m_start, m_end );
868 }
869 
870 
872 {
873  SCH_LINE* item = (SCH_LINE*) aItem;
874 
875  std::swap( m_layer, item->m_layer );
876 
877  std::swap( m_start, item->m_start );
878  std::swap( m_end, item->m_end );
879  std::swap( m_startIsDangling, item->m_startIsDangling );
880  std::swap( m_endIsDangling, item->m_endIsDangling );
881  std::swap( m_stroke, item->m_stroke );
882 }
883 
884 
885 bool SCH_LINE::doIsConnected( const wxPoint& aPosition ) const
886 {
887  if( m_layer != LAYER_WIRE && m_layer != LAYER_BUS )
888  return false;
889 
890  return IsEndPoint( aPosition );
891 }
892 
893 
894 void SCH_LINE::Plot( PLOTTER* aPlotter ) const
895 {
896  auto* settings = static_cast<KIGFX::SCH_RENDER_SETTINGS*>( aPlotter->RenderSettings() );
897  int penWidth = std::max( GetPenWidth(), settings->GetMinPenWidth() );
899 
900  if( color == COLOR4D::UNSPECIFIED )
901  color = settings->GetLayerColor( GetLayer() );
902 
903  aPlotter->SetColor( color );
904 
905  aPlotter->SetCurrentLineWidth( penWidth );
906  aPlotter->SetDash( GetEffectiveLineStyle() );
907 
908  aPlotter->MoveTo( m_start );
909  aPlotter->FinishTo( m_end );
910 
911  aPlotter->SetDash( PLOT_DASH_TYPE::SOLID );
912 }
913 
914 
915 void SCH_LINE::SetPosition( const wxPoint& aPosition )
916 {
917  m_end = m_end - ( m_start - aPosition );
918  m_start = aPosition;
919 }
920 
921 
922 void SCH_LINE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, std::vector<MSG_PANEL_ITEM>& aList )
923 {
924  wxString msg;
925 
926  switch( GetLayer() )
927  {
928  case LAYER_WIRE: msg = _( "Wire" ); break;
929  case LAYER_BUS: msg = _( "Bus" ); break;
930  default: msg = _( "Graphical" ); break;
931  }
932 
933  aList.emplace_back( _( "Line Type" ), msg );
934 
936  msg = _( "from netclass" );
937  else
938  msg = GetLineStyleName( GetLineStyle() );
939 
940  aList.emplace_back( _( "Line Style" ), msg );
941 
942  SCH_CONNECTION* conn = nullptr;
943 
944  if( !IsConnectivityDirty() && dynamic_cast<SCH_EDIT_FRAME*>( aFrame ) )
945  conn = Connection();
946 
947  if( conn )
948  {
949  conn->AppendInfoToMsgPanel( aList );
950 
951  if( !conn->IsBus() )
952  {
953  NET_SETTINGS& netSettings = Schematic()->Prj().GetProjectFile().NetSettings();
954  wxString netname = conn->Name();
955  wxString netclassName = netSettings.m_NetClasses.GetDefaultPtr()->GetName();
956 
957  if( netSettings.m_NetClassAssignments.count( netname ) )
958  netclassName = netSettings.m_NetClassAssignments[ netname ];
959 
960  aList.emplace_back( _( "Assigned Netclass" ), netclassName );
961  }
962  }
963 }
964 
965 
967 {
968  return ( GetLayer() == LAYER_NOTES );
969 }
970 
971 
972 bool SCH_LINE::IsWire() const
973 {
974  return ( GetLayer() == LAYER_WIRE );
975 }
976 
977 bool SCH_LINE::IsBus() const
978 {
979  return ( GetLayer() == LAYER_BUS );
980 }
981 
982 
984 {
985  return m_stroke.GetWidth() == 0 && m_stroke.GetColor() == COLOR4D::UNSPECIFIED
988 }
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:485
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:632
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:511
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:966
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:799
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:972
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:922
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:692
#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:762
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:833
bool UsesDefaultStroke() const
Test if the SCH_LINE object uses the default stroke settings.
Definition: sch_line.cpp:983
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:683
PLOT_DASH_TYPE GetDefaultStyle() const
Definition: sch_line.cpp:254
int GetAngleFrom(const wxPoint &aPoint) const
Definition: sch_line.cpp:472
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:885
void GetSelectedPoints(std::vector< wxPoint > &aPoints) const
Definition: sch_line.cpp:752
void Plot(PLOTTER *aPlotter) const override
Plot the schematic item to aPlotter.
Definition: sch_line.cpp:894
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:871
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:810
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:466
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:642
bool IsParallel(const SCH_LINE *aLine) const
Definition: sch_line.cpp:498
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:460
bool IsBus() const
void SetPosition(const wxPoint &aPosition) override
Definition: sch_line.cpp:915
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:977
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:733
bool ConnectionPropagatesTo(const EDA_ITEM *aItem) const override
Return true if this item should propagate connection info to aItem.
Definition: sch_line.cpp:739
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