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