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-2020 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( wxPoint aPosition )
396 {
397  RotatePoint( &m_start, aPosition, 900 );
398  RotatePoint( &m_end, aPosition, 900 );
399 }
400 
401 
402 void SCH_LINE::RotateStart( wxPoint aPosition )
403 {
404  RotatePoint( &m_start, aPosition, 900 );
405 }
406 
407 
408 void SCH_LINE::RotateEnd( wxPoint aPosition )
409 {
410  RotatePoint( &m_end, aPosition, 900 );
411 }
412 
413 
414 bool SCH_LINE::IsSameQuadrant( const SCH_LINE* aLine, const wxPoint& aPosition ) const
415 {
416  wxPoint first;
417  wxPoint second;
418 
419  if( m_start == aPosition )
420  first = m_end - aPosition;
421  else if( m_end == aPosition )
422  first = m_start - aPosition;
423  else
424  return false;
425 
426  if( aLine->m_start == aPosition )
427  second = aLine->m_end - aPosition;
428  else if( aLine->m_end == aPosition )
429  second = aLine->m_start - aPosition;
430  else
431  return false;
432 
433  return ( sign( first.x ) == sign( second.x ) && sign( first.y ) == sign( second.y ) );
434 }
435 
436 
437 bool SCH_LINE::IsParallel( const SCH_LINE* aLine ) const
438 {
439  wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, false,
440  wxT( "Cannot test line segment for overlap." ) );
441 
442  wxPoint firstSeg = m_end - m_start;
443  wxPoint secondSeg = aLine->m_end - aLine->m_start;
444 
445  // Use long long here to avoid overflow in calculations
446  return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x );
447 }
448 
449 
450 SCH_LINE* SCH_LINE::MergeOverlap( SCH_SCREEN* aScreen, SCH_LINE* aLine, bool aCheckJunctions )
451 {
452  auto less = []( const wxPoint& lhs, const wxPoint& rhs ) -> bool
453  {
454  if( lhs.x == rhs.x )
455  return lhs.y < rhs.y;
456 
457  return lhs.x < rhs.x;
458  };
459 
460  wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, NULL,
461  wxT( "Cannot test line segment for overlap." ) );
462 
463  if( this == aLine || GetLayer() != aLine->GetLayer() )
464  return nullptr;
465 
466  auto leftmost_start = aLine->m_start;
467  auto leftmost_end = aLine->m_end;
468 
469  auto rightmost_start = m_start;
470  auto rightmost_end = m_end;
471 
472  // We place the start to the left and below the end of both lines
473  if( leftmost_start != std::min( { leftmost_start, leftmost_end }, less ) )
474  std::swap( leftmost_start, leftmost_end );
475  if( rightmost_start != std::min( { rightmost_start, rightmost_end }, less ) )
476  std::swap( rightmost_start, rightmost_end );
477 
478  // - leftmost is the line that starts farthest to the left
479  // - other is the line that is _not_ leftmost
480  // - rightmost is the line that ends farthest to the right. This may or may not be 'other'
481  // as the second line may be completely covered by the first.
482  if( less( rightmost_start, leftmost_start ) )
483  {
484  std::swap( leftmost_start, rightmost_start );
485  std::swap( leftmost_end, rightmost_end );
486  }
487 
488  wxPoint other_start = rightmost_start;
489  wxPoint other_end = rightmost_end;
490 
491  if( less( rightmost_end, leftmost_end ) )
492  {
493  rightmost_start = leftmost_start;
494  rightmost_end = leftmost_end;
495  }
496 
497  // If we end one before the beginning of the other, no overlap is possible
498  if( less( leftmost_end, other_start ) )
499  {
500  return nullptr;
501  }
502 
503  // Search for a common end:
504  if( ( leftmost_start == other_start ) && ( leftmost_end == other_end ) ) // Trivial case
505  {
506  auto ret = new SCH_LINE( *aLine );
507  ret->SetStartPoint( leftmost_start );
508  ret->SetEndPoint( leftmost_end );
509 
510  if( IsSelected() || aLine->IsSelected() )
511  ret->SetSelected();
512 
513  return ret;
514  }
515 
516  bool colinear = false;
517 
518  /* Test alignment: */
519  if( ( leftmost_start.y == leftmost_end.y ) &&
520  ( other_start.y == other_end.y ) ) // Horizontal segment
521  {
522  colinear = ( leftmost_start.y == other_start.y );
523  }
524  else if( ( leftmost_start.x == leftmost_end.x ) &&
525  ( other_start.x == other_end.x ) ) // Vertical segment
526  {
527  colinear = ( leftmost_start.x == other_start.x );
528  }
529  else
530  {
531  // We use long long here to avoid overflow -- it enforces promotion
532  // The slope of the left-most line is dy/dx. Then we check that the slope from the
533  // left most start to the right most start is the same as well as the slope from the
534  // left most start to right most end.
535  long long dx = leftmost_end.x - leftmost_start.x;
536  long long dy = leftmost_end.y - leftmost_start.y;
537  colinear = ( ( ( other_start.y - leftmost_start.y ) * dx ==
538  ( other_start.x - leftmost_start.x ) * dy ) &&
539  ( ( other_end.y - leftmost_start.y ) * dx ==
540  ( other_end.x - leftmost_start.x ) * dy ) );
541  }
542 
543  if( !colinear )
544  return nullptr;
545 
546  // We either have a true overlap or colinear touching segments. We always want to merge
547  // the former, but the later only get merged if there no junction at the touch point.
548 
549  bool touching = leftmost_end == rightmost_start;
550 
551  if( touching && aCheckJunctions && aScreen->IsJunctionNeeded( leftmost_end ) )
552  return nullptr;
553 
554  // Make a new segment that merges the 2 segments
555  leftmost_end = rightmost_end;
556 
557  auto ret = new SCH_LINE( *aLine );
558  ret->SetStartPoint( leftmost_start );
559  ret->SetEndPoint( leftmost_end );
560 
561  if( IsSelected() || aLine->IsSelected() )
562  ret->SetSelected();
563 
564  return ret;
565 }
566 
567 
568 void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
569 {
570  DANGLING_END_T startType, endType;
571 
572  switch( GetLayer() )
573  {
574  case LAYER_WIRE:
575  startType = WIRE_START_END;
576  endType = WIRE_END_END;
577  break;
578  case LAYER_BUS:
579  startType = BUS_START_END;
580  endType = BUS_END_END;
581  break;
582  default:
583  startType = GRAPHIC_START_END;
584  endType = GRAPHIC_END_END;
585  break;
586  }
587 
588  DANGLING_END_ITEM item( startType, this, m_start );
589  aItemList.push_back( item );
590 
591  DANGLING_END_ITEM item1( endType, this, m_end );
592  aItemList.push_back( item1 );
593 }
594 
595 
596 bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
597  const SCH_SHEET_PATH* aPath )
598 {
599  bool previousStartState = m_startIsDangling;
600  bool previousEndState = m_endIsDangling;
601 
603 
604  for( DANGLING_END_ITEM item : aItemList )
605  {
606  if( item.GetItem() == this )
607  continue;
608 
609  if( ( IsWire()
610  && ( item.GetType() == BUS_START_END || item.GetType() == BUS_END_END
611  || item.GetType() == BUS_ENTRY_END ) )
612  || ( IsBus()
613  && ( item.GetType() == WIRE_START_END || item.GetType() == WIRE_END_END
614  || item.GetType() == PIN_END ) )
615  || ( IsGraphicLine()
616  && ( item.GetType() != GRAPHIC_START_END && item.GetType() != GRAPHIC_END_END ) ) )
617  continue;
618 
619  if( m_start == item.GetPosition() )
620  m_startIsDangling = false;
621 
622  if( m_end == item.GetPosition() )
623  m_endIsDangling = false;
624 
626  break;
627  }
628 
629  if( IsBus() || IsGraphicLine() )
630  {
631  // Force unchanged return state for graphic lines and busses
632  previousStartState = m_startIsDangling;
633  previousEndState = m_endIsDangling;
634  }
635 
636  return ( previousStartState != m_startIsDangling ) || ( previousEndState != m_endIsDangling );
637 }
638 
639 
641 {
642  if( m_layer == LAYER_WIRE || m_layer == LAYER_BUS )
643  return true;
644 
645  return false;
646 }
647 
648 
649 bool SCH_LINE::CanConnect( const SCH_ITEM* aItem ) const
650 {
651  if( m_layer == LAYER_WIRE )
652  {
653  switch( aItem->Type() )
654  {
655  case SCH_JUNCTION_T:
656  case SCH_NO_CONNECT_T:
657  case SCH_LABEL_T:
658  case SCH_GLOBAL_LABEL_T:
659  case SCH_HIER_LABEL_T:
661  case SCH_COMPONENT_T:
662  case SCH_SHEET_T:
663  case SCH_SHEET_PIN_T:
664  return true;
665  default:
666  break;
667  }
668  }
669  else if( m_layer == LAYER_BUS )
670  {
671  switch( aItem->Type() )
672  {
673  case SCH_JUNCTION_T:
674  case SCH_LABEL_T:
675  case SCH_GLOBAL_LABEL_T:
676  case SCH_HIER_LABEL_T:
678  case SCH_SHEET_T:
679  case SCH_SHEET_PIN_T:
680  return true;
681  default:
682  break;
683  }
684  }
685 
686  return aItem->GetLayer() == m_layer;
687 }
688 
689 
690 std::vector<wxPoint> SCH_LINE::GetConnectionPoints() const
691 {
692  return { m_start, m_end };
693 }
694 
695 
696 void SCH_LINE::GetSelectedPoints( std::vector< wxPoint >& aPoints ) const
697 {
698  if( m_flags & STARTPOINT )
699  aPoints.push_back( m_start );
700 
701  if( m_flags & ENDPOINT )
702  aPoints.push_back( m_end );
703 }
704 
705 
706 wxString SCH_LINE::GetSelectMenuText( EDA_UNITS aUnits ) const
707 {
708  wxString txtfmt, orient;
709 
710  if( m_start.x == m_end.x )
711  {
712  switch( m_layer )
713  {
714  case LAYER_WIRE: txtfmt = _( "Vertical Wire, length %s" ); break;
715  case LAYER_BUS: txtfmt = _( "Vertical Bus, length %s" ); break;
716  default: txtfmt = _( "Vertical Graphic Line, length %s" ); break;
717  }
718  }
719  else if( m_start.y == m_end.y )
720  {
721  switch( m_layer )
722  {
723  case LAYER_WIRE: txtfmt = _( "Horizontal Wire, length %s" ); break;
724  case LAYER_BUS: txtfmt = _( "Horizontal Bus, length %s" ); break;
725  default: txtfmt = _( "Horizontal Graphic Line, length %s" ); break;
726  }
727  }
728  else
729  {
730  switch( m_layer )
731  {
732  case LAYER_WIRE: txtfmt = _( "Wire, length %s" ); break;
733  case LAYER_BUS: txtfmt = _( "Bus, length %s" ); break;
734  default: txtfmt = _( "Graphic Line, length %s" ); break;
735  }
736  }
737 
738  return wxString::Format( txtfmt,
740 }
741 
742 
744 {
745  if( m_layer == LAYER_NOTES )
746  return add_dashed_line_xpm;
747  else if( m_layer == LAYER_WIRE )
748  return add_line_xpm;
749 
750  return add_bus_xpm;
751 }
752 
753 
754 bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
755 {
756  if( Type() != aItem.Type() )
757  return Type() < aItem.Type();
758 
759  auto line = static_cast<const SCH_LINE*>( &aItem );
760 
761  if( GetLayer() != line->GetLayer() )
762  return GetLayer() < line->GetLayer();
763 
764  if( GetStartPoint().x != line->GetStartPoint().x )
765  return GetStartPoint().x < line->GetStartPoint().x;
766 
767  if( GetStartPoint().y != line->GetStartPoint().y )
768  return GetStartPoint().y < line->GetStartPoint().y;
769 
770  if( GetEndPoint().x != line->GetEndPoint().x )
771  return GetEndPoint().x < line->GetEndPoint().x;
772 
773  return GetEndPoint().y < line->GetEndPoint().y;
774 }
775 
776 
777 bool SCH_LINE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
778 {
779  // Performance enhancement for connection-building
780  if( aPosition == m_start || aPosition == m_end )
781  return true;
782 
783  aAccuracy += GetPenWidth() / 2;
784 
785  return TestSegmentHit( aPosition, m_start, m_end, aAccuracy );
786 }
787 
788 
789 bool SCH_LINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
790 {
791  if( m_flags & (STRUCT_DELETED | SKIP_STRUCT ) )
792  return false;
793 
794  EDA_RECT rect = aRect;
795 
796  if ( aAccuracy )
797  rect.Inflate( aAccuracy );
798 
799  if( aContained )
800  return rect.Contains( m_start ) && rect.Contains( m_end );
801 
802  return rect.Intersects( m_start, m_end );
803 }
804 
805 
807 {
808  SCH_LINE* item = (SCH_LINE*) aItem;
809 
810  std::swap( m_layer, item->m_layer );
811 
812  std::swap( m_start, item->m_start );
813  std::swap( m_end, item->m_end );
814  std::swap( m_startIsDangling, item->m_startIsDangling );
815  std::swap( m_endIsDangling, item->m_endIsDangling );
816  std::swap( m_stroke, item->m_stroke );
817 }
818 
819 
820 bool SCH_LINE::doIsConnected( const wxPoint& aPosition ) const
821 {
822  if( m_layer != LAYER_WIRE && m_layer != LAYER_BUS )
823  return false;
824 
825  return IsEndPoint( aPosition );
826 }
827 
828 
829 void SCH_LINE::Plot( PLOTTER* aPlotter )
830 {
831  auto* settings = static_cast<KIGFX::SCH_RENDER_SETTINGS*>( aPlotter->RenderSettings() );
832  int penWidth;
834 
835  if( color == COLOR4D::UNSPECIFIED )
836  color = settings->GetLayerColor( GetLayer() );
837 
838  aPlotter->SetColor( color );
839 
840  switch( m_layer )
841  {
842  case LAYER_WIRE: penWidth = settings->m_DefaultWireThickness; break;
843  case LAYER_BUS: penWidth = settings->m_DefaultBusThickness; break;
844  default: penWidth = GetPenWidth(); break;
845  }
846 
847  if( m_stroke.GetWidth() != 0 )
848  penWidth = m_stroke.GetWidth();
849 
850  penWidth = std::max( penWidth, settings->GetMinPenWidth() );
851 
852  aPlotter->SetCurrentLineWidth( penWidth );
853  aPlotter->SetDash( GetEffectiveLineStyle() );
854 
855  aPlotter->MoveTo( m_start );
856  aPlotter->FinishTo( m_end );
857 
858  aPlotter->SetDash( PLOT_DASH_TYPE::SOLID );
859 }
860 
861 
862 void SCH_LINE::SetPosition( const wxPoint& aPosition )
863 {
864  m_end = m_end - ( m_start - aPosition );
865  m_start = aPosition;
866 }
867 
868 
870 {
871  wxString msg;
872 
873  switch( GetLayer() )
874  {
875  case LAYER_WIRE: msg = _( "Wire" ); break;
876  case LAYER_BUS: msg = _( "Bus" ); break;
877  default: msg = _( "Graphical" ); break;
878  }
879 
880  aList.push_back( MSG_PANEL_ITEM( _( "Line Type" ), msg ) );
881 
883  msg = _( "from netclass" );
884  else
885  msg = GetLineStyleName( GetLineStyle() );
886 
887  aList.push_back( MSG_PANEL_ITEM( _( "Line Style" ), msg ) );
888 
889  SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
890 
891  if( frame )
892  {
893  if( SCH_CONNECTION* conn = Connection() )
894  {
895  conn->AppendInfoToMsgPanel( aList );
896 
897  NET_SETTINGS& netSettings = Schematic()->Prj().GetProjectFile().NetSettings();
898  wxString netname = conn->Name();
899  wxString netclassName = netSettings.m_NetClasses.GetDefaultPtr()->GetName();
900 
901  if( netSettings.m_NetClassAssignments.count( netname ) )
902  netclassName = netSettings.m_NetClassAssignments[ netname ];
903 
904  aList.push_back( MSG_PANEL_ITEM( _( "Assigned Netclass" ), netclassName ) );
905  }
906  }
907 }
908 
909 
911 {
912  return ( GetLayer() == LAYER_NOTES );
913 }
914 
915 
916 bool SCH_LINE::IsWire() const
917 {
918  return ( GetLayer() == LAYER_WIRE );
919 }
920 
921 bool SCH_LINE::IsBus() const
922 {
923  return ( GetLayer() == LAYER_BUS );
924 }
925 
926 
928 {
929  return m_stroke.GetWidth() == 0 && m_stroke.GetColor() == COLOR4D::UNSPECIFIED
932 }
double EuclideanNorm(const wxPoint &vector)
Euclidean norm of a 2D vector.
Definition: trigo.h:148
void Rotate(wxPoint aPosition) override
Rotate the item around aPosition 90 degrees in the clockwise direction.
Definition: sch_line.cpp:395
void FinishTo(const wxPoint &pos)
Definition: plotter.h:267
CITER next(CITER it)
Definition: ptree.cpp:126
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:568
static const char * GetLineStyleName(PLOT_DASH_TYPE aStyle)
Definition: sch_line.cpp:85
int sign(T val)
Definition: util.h:101
void SetModified()
Definition: eda_item.cpp:79
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:450
std::map< wxString, wxString > m_NetClassAssignments
Definition: net_settings.h:43
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:125
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:172
Plot settings, and plotting engines (PostScript, Gerber, HPGL and DXF)
wxString GetClass() const override
Return the class name.
Definition: sch_line.h:64
bool IsGraphicLine() const
Returns if the line is a graphic (non electrical line)
Definition: sch_line.cpp:910
double GetLineLength(const wxPoint &aPointA, const wxPoint &aPointB)
Return the length of a line segment defined by aPointA and aPointB.
Definition: trigo.h:223
PNG memory record (file in memory).
Definition: bitmap_def.h:29
const BITMAP_OPAQUE add_dashed_line_xpm[1]
wxPoint GetStartPoint() const
Definition: sch_line.h:94
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
bool IsWire() const
Returns true if the line is a wire.
Definition: sch_line.cpp:916
bool IsSelected() const
Definition: eda_item.h:172
bool IsJunctionNeeded(const wxPoint &aPosition, bool aNew=false)
Test if a junction is required for the items at aPosition on the screen.
Definition: sch_screen.cpp:373
virtual void SetColor(COLOR4D color)=0
const wxString & GetName() const
Definition: netclass.h:65
bool m_endIsDangling
True if end point is not connected.
Definition: sch_line.h:40
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 RotateEnd(wxPoint aPosition)
Definition: sch_line.cpp:408
void MoveStart(const wxPoint &aMoveVector)
Definition: sch_line.cpp:121
SCHEMATIC_SETTINGS & Settings() const
Definition: schematic.cpp:125
int color
Definition: DXF_plotter.cpp:60
SCHEMATIC * Schematic() const
Searches the item hierarchy to find a SCHEMATIC.
Definition: sch_item.cpp:97
void Plot(PLOTTER *aPlotter) override
Plot the schematic item to aPlotter.
Definition: sch_line.cpp:829
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:869
NET_SETTINGS & NetSettings()
Definition: project_file.h:92
#define DASH_MARK_LEN(aLineWidth)
Schematic editor (Eeschema) main window.
void SetPlotStyle(PLOT_DASH_TYPE aPlotStyle)
Definition: sch_item.h:175
bool CanConnect(const SCH_ITEM *aItem) const override
Definition: sch_line.cpp:649
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:706
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:777
void RotateStart(wxPoint aPosition)
Definition: sch_line.cpp:402
bool UsesDefaultStroke() const
Test if the SCH_LINE object uses the default stroke settings.
Definition: sch_line.cpp:927
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:640
PLOT_DASH_TYPE GetDefaultStyle() const
Definition: sch_line.cpp:224
void SetLineStyle(const PLOT_DASH_TYPE aStyle)
Definition: sch_line.cpp:239
double a
Alpha component.
Definition: color4d.h:361
SCH_LAYER_ID m_layer
Definition: sch_item.h:201
NETCLASSES m_NetClasses
Definition: net_settings.h:39
#define NULL
const std::map< PLOT_DASH_TYPE, const char * > lineStyleNames
Definition: sch_line.cpp:77
BITMAP_DEF GetMenuImage() const override
Return a pointer to an image to be used in menus.
Definition: sch_line.cpp:743
PLOT_DASH_TYPE GetLineStyle() const
Definition: sch_line.cpp:248
const BITMAP_OPAQUE add_line_xpm[1]
Definition: add_line.cpp:19
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:39
int GetPenWidth() const override
Definition: sch_line.cpp:277
PLOT_DASH_TYPE GetPlotStyle() const
Definition: sch_item.h:174
NET_SETTINGS stores various net-related settings in a project context.
Definition: net_settings.h:31
wxDC * GetPrintDC() const
void SetLineColor(const COLOR4D &aColor)
Definition: sch_line.cpp:189
bool IsEndPoint(const wxPoint &aPoint) const
Definition: sch_line.h:87
#define STRUCT_DELETED
flag indication structures to be erased
Definition: eda_item.h:115
int GetWidth() const
Definition: sch_item.h:171
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:820
void GetSelectedPoints(std::vector< wxPoint > &aPoints) const
Definition: sch_line.cpp:696
#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:42
void SwapData(SCH_ITEM *aItem) override
Swap the internal data structures aItem with the schematic item.
Definition: sch_line.cpp:806
STROKE_PARAMS m_stroke
Line stroke properties.
Definition: sch_line.h:43
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:99
#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:287
void MoveTo(const wxPoint &pos)
Definition: plotter.h:257
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
#define STARTPOINT
When a line is selected, these flags indicate which.
Definition: eda_item.h:111
Base plotter engine class.
Definition: plotter.h:121
COLOR4D GetColor() const
Definition: sch_item.h:177
RENDER_SETTINGS * RenderSettings()
Definition: plotter.h:155
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
void MoveEnd(const wxPoint &aMoveVector)
Definition: sch_line.cpp:131
bool operator<(const SCH_ITEM &aItem) const override
Definition: sch_line.cpp:754
Each graphical item can have a SCH_CONNECTION describing its logical connection (to a bus or net).
#define _(s)
Definition: 3d_actions.cpp:33
#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:68
#define DASH_GAP_LEN(aLineWidth)
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:149
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
const BITMAP_OPAQUE add_bus_xpm[1]
Definition: add_bus.cpp:22
int GetDefaultPenWidth() const
void SetColor(const COLOR4D &aColor)
Definition: sch_item.h:178
#define ENDPOINT
ends. (Used to support dragging.)
Definition: eda_item.h:112
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:596
bool IsParallel(const SCH_LINE *aLine) const
Definition: sch_line.cpp:437
bool IsSameQuadrant(const SCH_LINE *aLine, const wxPoint &aPosition) const
Check if two lines are in the same quadrant as each other, using a reference point as the origin.
Definition: sch_line.cpp:414
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
EDA_MSG_ITEM is used EDA_MSG_PANEL as the item type for displaying messages.
Definition: msgpanel.h:54
#define SKIP_STRUCT
flag indicating that the structure should be ignored
Definition: eda_item.h:117
void SetPosition(const wxPoint &aPosition) override
Definition: sch_line.cpp:862
STATUS_FLAGS m_flags
Definition: eda_item.h:530
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:196
wxPoint m_start
Line start point.
Definition: sch_line.h:41
bool IsBus() const
Returns true if the line is a bus.
Definition: sch_line.cpp:921
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:363
std::vector< wxPoint > GetConnectionPoints() const override
Add all the connection points for this item to aPoints.
Definition: sch_line.cpp:690
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:162
virtual void SetCurrentLineWidth(int width, void *aData=NULL)=0
Set the line width for the next drawing.
A color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:98
wxPoint GetEndPoint() const
Definition: sch_line.h:97