You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

863 lines
23 KiB

  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. #include <fctsys.h>
  25. #include <sch_painter.h>
  26. #include <plotter.h>
  27. #include <sch_line.h>
  28. #include <sch_edit_frame.h>
  29. #include <settings/color_settings.h>
  30. #include <schematic.h>
  31. #include <project/project_file.h>
  32. #include <project/net_settings.h>
  33. SCH_LINE::SCH_LINE( const wxPoint& pos, int layer ) :
  34. SCH_ITEM( NULL, SCH_LINE_T )
  35. {
  36. m_start = pos;
  37. m_end = pos;
  38. m_startIsDangling = m_endIsDangling = false;
  39. m_stroke.SetWidth( 0 );
  40. m_stroke.SetType( PLOT_DASH_TYPE::DEFAULT );
  41. m_stroke.SetColor( COLOR4D::UNSPECIFIED );
  42. switch( layer )
  43. {
  44. default: m_Layer = LAYER_NOTES; break;
  45. case LAYER_WIRE: m_Layer = LAYER_WIRE; break;
  46. case LAYER_BUS: m_Layer = LAYER_BUS; break;
  47. }
  48. }
  49. SCH_LINE::SCH_LINE( const SCH_LINE& aLine ) :
  50. SCH_ITEM( aLine )
  51. {
  52. m_start = aLine.m_start;
  53. m_end = aLine.m_end;
  54. m_stroke = aLine.m_stroke;
  55. m_startIsDangling = aLine.m_startIsDangling;
  56. m_endIsDangling = aLine.m_endIsDangling;
  57. }
  58. EDA_ITEM* SCH_LINE::Clone() const
  59. {
  60. return new SCH_LINE( *this );
  61. }
  62. /*
  63. * Conversion between PLOT_DASH_TYPE values and style names displayed
  64. */
  65. const std::map<PLOT_DASH_TYPE, const char*> lineStyleNames{
  66. { PLOT_DASH_TYPE::SOLID, "solid" },
  67. { PLOT_DASH_TYPE::DASH, "dashed" },
  68. { PLOT_DASH_TYPE::DASHDOT, "dash_dot" },
  69. { PLOT_DASH_TYPE::DOT, "dotted" },
  70. };
  71. const char* SCH_LINE::GetLineStyleName( PLOT_DASH_TYPE aStyle )
  72. {
  73. auto resultIt = lineStyleNames.find( aStyle );
  74. //legacy behavior is to default to dash if there is no name
  75. return resultIt == lineStyleNames.end() ? lineStyleNames.find( PLOT_DASH_TYPE::DASH )->second :
  76. resultIt->second;
  77. }
  78. PLOT_DASH_TYPE SCH_LINE::GetLineStyleByName( const wxString& aStyleName )
  79. {
  80. PLOT_DASH_TYPE id = PLOT_DASH_TYPE::DEFAULT; // Default style id
  81. //find the name by value
  82. auto resultIt = std::find_if( lineStyleNames.begin(), lineStyleNames.end(),
  83. [aStyleName]( const auto& it ) { return it.second == aStyleName; } );
  84. if( resultIt != lineStyleNames.end() )
  85. id = resultIt->first;
  86. return id;
  87. }
  88. void SCH_LINE::Move( const wxPoint& aOffset )
  89. {
  90. if( aOffset != wxPoint( 0, 0 ) )
  91. {
  92. m_start += aOffset;
  93. m_end += aOffset;
  94. SetModified();
  95. }
  96. }
  97. void SCH_LINE::MoveStart( const wxPoint& aOffset )
  98. {
  99. if( aOffset != wxPoint( 0, 0 ) )
  100. {
  101. m_start += aOffset;
  102. SetModified();
  103. }
  104. }
  105. void SCH_LINE::MoveEnd( const wxPoint& aOffset )
  106. {
  107. if( aOffset != wxPoint( 0, 0 ) )
  108. {
  109. m_end += aOffset;
  110. SetModified();
  111. }
  112. }
  113. #if defined(DEBUG)
  114. void SCH_LINE::Show( int nestLevel, std::ostream& os ) const
  115. {
  116. NestedSpace( nestLevel, os ) << '<' << GetClass().Lower().mb_str()
  117. << " layer=\"" << m_Layer << '"'
  118. << " startIsDangling=\"" << m_startIsDangling
  119. << '"' << " endIsDangling=\""
  120. << m_endIsDangling << '"' << ">"
  121. << " <start" << m_start << "/>"
  122. << " <end" << m_end << "/>" << "</"
  123. << GetClass().Lower().mb_str() << ">\n";
  124. }
  125. #endif
  126. void SCH_LINE::ViewGetLayers( int aLayers[], int& aCount ) const
  127. {
  128. aCount = 2;
  129. aLayers[0] = m_Layer;
  130. aLayers[1] = LAYER_SELECTION_SHADOWS;
  131. }
  132. const EDA_RECT SCH_LINE::GetBoundingBox() const
  133. {
  134. int width = m_stroke.GetWidth() / 2;
  135. int extra = m_stroke.GetWidth() & 0x1;
  136. int xmin = std::min( m_start.x, m_end.x ) - width;
  137. int ymin = std::min( m_start.y, m_end.y ) - width;
  138. int xmax = std::max( m_start.x, m_end.x ) + width + extra;
  139. int ymax = std::max( m_start.y, m_end.y ) + width + extra;
  140. EDA_RECT ret( wxPoint( xmin, ymin ), wxSize( xmax - xmin, ymax - ymin ) );
  141. return ret;
  142. }
  143. double SCH_LINE::GetLength() const
  144. {
  145. return GetLineLength( m_start, m_end );
  146. }
  147. void SCH_LINE::SetLineColor( const COLOR4D& aColor )
  148. {
  149. m_stroke.SetColor( aColor );
  150. }
  151. void SCH_LINE::SetLineColor( const double r, const double g, const double b, const double a )
  152. {
  153. COLOR4D newColor(r, g, b, a);
  154. if( newColor == COLOR4D::UNSPECIFIED )
  155. m_stroke.SetColor( COLOR4D::UNSPECIFIED );
  156. else
  157. {
  158. // Eeschema does not allow alpha channel in colors
  159. newColor.a = 1.0;
  160. m_stroke.SetColor( newColor );
  161. }
  162. }
  163. COLOR4D SCH_LINE::GetLineColor() const
  164. {
  165. if( m_stroke.GetColor() != COLOR4D::UNSPECIFIED )
  166. return m_stroke.GetColor();
  167. NETCLASSPTR netclass = NetClass();
  168. if( netclass )
  169. return netclass->GetSchematicColor();
  170. return m_stroke.GetColor();
  171. }
  172. PLOT_DASH_TYPE SCH_LINE::GetDefaultStyle() const
  173. {
  174. if( IsGraphicLine() )
  175. return PLOT_DASH_TYPE::DASH;
  176. return PLOT_DASH_TYPE::SOLID;
  177. }
  178. void SCH_LINE::SetLineStyle( const int aStyleId )
  179. {
  180. SetLineStyle( static_cast<PLOT_DASH_TYPE>( aStyleId ) );
  181. }
  182. void SCH_LINE::SetLineStyle( const PLOT_DASH_TYPE aStyle )
  183. {
  184. if( aStyle == GetDefaultStyle() )
  185. m_stroke.SetType( PLOT_DASH_TYPE::DEFAULT );
  186. else
  187. m_stroke.SetType( aStyle );
  188. }
  189. PLOT_DASH_TYPE SCH_LINE::GetLineStyle() const
  190. {
  191. if( m_stroke.GetType() != PLOT_DASH_TYPE::DEFAULT )
  192. return m_stroke.GetType();
  193. return GetDefaultStyle();
  194. }
  195. PLOT_DASH_TYPE SCH_LINE::GetEffectiveLineStyle() const
  196. {
  197. if( m_stroke.GetType() != PLOT_DASH_TYPE::DEFAULT )
  198. return m_stroke.GetType();
  199. NETCLASSPTR netclass = NetClass();
  200. if( netclass )
  201. return (PLOT_DASH_TYPE) netclass->GetLineStyle();
  202. return GetLineStyle();
  203. }
  204. void SCH_LINE::SetLineWidth( const int aSize )
  205. {
  206. m_stroke.SetWidth( aSize );
  207. }
  208. int SCH_LINE::GetPenWidth() const
  209. {
  210. NETCLASSPTR netclass = NetClass();
  211. switch ( m_Layer )
  212. {
  213. default:
  214. if( m_stroke.GetWidth() > 0 )
  215. return m_stroke.GetWidth();
  216. if( Schematic() )
  217. return Schematic()->Settings().m_DefaultLineWidth;
  218. return DEFAULT_LINE_THICKNESS;
  219. case LAYER_WIRE:
  220. if( m_stroke.GetWidth() > 0 )
  221. return m_stroke.GetWidth();
  222. if( netclass )
  223. return netclass->GetWireWidth();
  224. if( Schematic() )
  225. return Schematic()->Settings().m_DefaultWireThickness;
  226. return DEFAULT_WIRE_THICKNESS;
  227. case LAYER_BUS:
  228. if( m_stroke.GetWidth() > 0 )
  229. return m_stroke.GetWidth();
  230. if( netclass )
  231. return netclass->GetBusWidth();
  232. if( Schematic() )
  233. return Schematic()->Settings().m_DefaultBusThickness;
  234. return DEFAULT_BUS_THICKNESS;
  235. }
  236. }
  237. void SCH_LINE::Print( RENDER_SETTINGS* aSettings, const wxPoint& offset )
  238. {
  239. wxDC* DC = aSettings->GetPrintDC();
  240. COLOR4D color = GetLineColor();
  241. if( color == COLOR4D::UNSPECIFIED )
  242. color = aSettings->GetLayerColor( GetLayer() );
  243. wxPoint start = m_start;
  244. wxPoint end = m_end;
  245. int penWidth = std::max( GetPenWidth(), aSettings->GetDefaultPenWidth() );
  246. GRLine( nullptr, DC, start.x, start.y, end.x, end.y, penWidth, color,
  247. GetwxPenStyle( GetEffectiveLineStyle() ) );
  248. }
  249. void SCH_LINE::MirrorX( int aXaxis_position )
  250. {
  251. MIRROR( m_start.y, aXaxis_position );
  252. MIRROR( m_end.y, aXaxis_position );
  253. }
  254. void SCH_LINE::MirrorY( int aYaxis_position )
  255. {
  256. MIRROR( m_start.x, aYaxis_position );
  257. MIRROR( m_end.x, aYaxis_position );
  258. }
  259. void SCH_LINE::Rotate( wxPoint aPosition )
  260. {
  261. RotatePoint( &m_start, aPosition, 900 );
  262. RotatePoint( &m_end, aPosition, 900 );
  263. }
  264. void SCH_LINE::RotateStart( wxPoint aPosition )
  265. {
  266. RotatePoint( &m_start, aPosition, 900 );
  267. }
  268. void SCH_LINE::RotateEnd( wxPoint aPosition )
  269. {
  270. RotatePoint( &m_end, aPosition, 900 );
  271. }
  272. bool SCH_LINE::IsSameQuadrant( SCH_LINE* aLine, const wxPoint& aPosition )
  273. {
  274. wxPoint first;
  275. wxPoint second;
  276. if( m_start == aPosition )
  277. first = m_end - aPosition;
  278. else if( m_end == aPosition )
  279. first = m_start - aPosition;
  280. else
  281. return false;
  282. if( aLine->m_start == aPosition )
  283. second = aLine->m_end - aPosition;
  284. else if( aLine->m_end == aPosition )
  285. second = aLine->m_start - aPosition;
  286. else
  287. return false;
  288. return ( sign( first.x ) == sign( second.x ) && sign( first.y ) == sign( second.y ) );
  289. }
  290. bool SCH_LINE::IsParallel( SCH_LINE* aLine )
  291. {
  292. wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, false,
  293. wxT( "Cannot test line segment for overlap." ) );
  294. wxPoint firstSeg = m_end - m_start;
  295. wxPoint secondSeg = aLine->m_end - aLine->m_start;
  296. // Use long long here to avoid overflow in calculations
  297. return !( (long long) firstSeg.x * secondSeg.y - (long long) firstSeg.y * secondSeg.x );
  298. }
  299. SCH_LINE* SCH_LINE::MergeOverlap( SCH_LINE* aLine )
  300. {
  301. auto less = []( const wxPoint& lhs, const wxPoint& rhs ) -> bool
  302. {
  303. if( lhs.x == rhs.x )
  304. return lhs.y < rhs.y;
  305. return lhs.x < rhs.x;
  306. };
  307. wxCHECK_MSG( aLine != NULL && aLine->Type() == SCH_LINE_T, NULL,
  308. wxT( "Cannot test line segment for overlap." ) );
  309. if( this == aLine || GetLayer() != aLine->GetLayer() )
  310. return nullptr;
  311. auto leftmost_start = aLine->m_start;
  312. auto leftmost_end = aLine->m_end;
  313. auto rightmost_start = m_start;
  314. auto rightmost_end = m_end;
  315. // We place the start to the left and below the end of both lines
  316. if( leftmost_start != std::min( { leftmost_start, leftmost_end }, less ) )
  317. std::swap( leftmost_start, leftmost_end );
  318. if( rightmost_start != std::min( { rightmost_start, rightmost_end }, less ) )
  319. std::swap( rightmost_start, rightmost_end );
  320. // -leftmost is the line that starts farthest to the left
  321. // -other is the line that is _not_ leftmost
  322. // -rightmost is the line that ends farthest to the right. This may or
  323. // may not be 'other' as the second line may be completely covered by
  324. // the first.
  325. if( less( rightmost_start, leftmost_start ) )
  326. {
  327. std::swap( leftmost_start, rightmost_start );
  328. std::swap( leftmost_end, rightmost_end );
  329. }
  330. auto other_start = rightmost_start;
  331. auto other_end = rightmost_end;
  332. if( less( rightmost_end, leftmost_end ) )
  333. {
  334. rightmost_start = leftmost_start;
  335. rightmost_end = leftmost_end;
  336. }
  337. // If we end one before the beginning of the other, no overlap is possible
  338. if( less( leftmost_end, other_start ) )
  339. {
  340. return nullptr;
  341. }
  342. // Search for a common end:
  343. if( ( leftmost_start == other_start ) && ( leftmost_end == other_end ) ) // Trivial case
  344. {
  345. auto ret = new SCH_LINE( *aLine );
  346. ret->SetStartPoint( leftmost_start );
  347. ret->SetEndPoint( leftmost_end );
  348. if( IsSelected() || aLine->IsSelected() )
  349. ret->SetSelected();
  350. return ret;
  351. }
  352. bool colinear = false;
  353. /* Test alignment: */
  354. if( ( leftmost_start.y == leftmost_end.y ) &&
  355. ( other_start.y == other_end.y ) ) // Horizontal segment
  356. {
  357. colinear = ( leftmost_start.y == other_start.y );
  358. }
  359. else if( ( leftmost_start.x == leftmost_end.x ) &&
  360. ( other_start.x == other_end.x ) ) // Vertical segment
  361. {
  362. colinear = ( leftmost_start.x == other_start.x );
  363. }
  364. else
  365. {
  366. // We use long long here to avoid overflow -- it enforces promotion
  367. // Don't use double as we need to make a direct comparison
  368. // The slope of the left-most line is dy/dx. Then we check that the slope
  369. // from the left most start to the right most start is the same as well as
  370. // the slope from the left most start to right most end.
  371. long long dx = leftmost_end.x - leftmost_start.x;
  372. long long dy = leftmost_end.y - leftmost_start.y;
  373. colinear = ( ( ( other_start.y - leftmost_start.y ) * dx ==
  374. ( other_start.x - leftmost_start.x ) * dy ) &&
  375. ( ( other_end.y - leftmost_start.y ) * dx ==
  376. ( other_end.x - leftmost_start.x ) * dy ) );
  377. }
  378. // Make a new segment that merges the 2 segments
  379. if( colinear )
  380. {
  381. leftmost_end = rightmost_end;
  382. auto ret = new SCH_LINE( *aLine );
  383. ret->SetStartPoint( leftmost_start );
  384. ret->SetEndPoint( leftmost_end );
  385. if( IsSelected() || aLine->IsSelected() )
  386. ret->SetSelected();
  387. return ret;
  388. }
  389. return nullptr;
  390. }
  391. void SCH_LINE::GetEndPoints( std::vector <DANGLING_END_ITEM>& aItemList )
  392. {
  393. if( IsGraphicLine() )
  394. return;
  395. if( ( GetLayer() == LAYER_BUS ) || ( GetLayer() == LAYER_WIRE ) )
  396. {
  397. DANGLING_END_ITEM item( (GetLayer() == LAYER_BUS) ? BUS_START_END : WIRE_START_END, this,
  398. m_start );
  399. aItemList.push_back( item );
  400. DANGLING_END_ITEM item1( (GetLayer() == LAYER_BUS) ? BUS_END_END : WIRE_END_END, this,
  401. m_end );
  402. aItemList.push_back( item1 );
  403. }
  404. }
  405. bool SCH_LINE::UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemList,
  406. const SCH_SHEET_PATH* aPath )
  407. {
  408. bool previousStartState = m_startIsDangling;
  409. bool previousEndState = m_endIsDangling;
  410. m_startIsDangling = m_endIsDangling = true;
  411. if( GetLayer() == LAYER_WIRE )
  412. {
  413. for( DANGLING_END_ITEM item : aItemList )
  414. {
  415. if( item.GetItem() == this )
  416. continue;
  417. if( item.GetType() == BUS_START_END ||
  418. item.GetType() == BUS_END_END ||
  419. item.GetType() == BUS_ENTRY_END )
  420. continue;
  421. if( m_start == item.GetPosition() )
  422. m_startIsDangling = false;
  423. if( m_end == item.GetPosition() )
  424. m_endIsDangling = false;
  425. if( !m_startIsDangling && !m_endIsDangling )
  426. break;
  427. }
  428. }
  429. else if( GetLayer() == LAYER_BUS || IsGraphicLine() )
  430. {
  431. // Lines on the notes layer and the bus layer cannot be tested for dangling ends.
  432. previousStartState = previousEndState = m_startIsDangling = m_endIsDangling = false;
  433. }
  434. return ( previousStartState != m_startIsDangling ) || ( previousEndState != m_endIsDangling );
  435. }
  436. bool SCH_LINE::IsConnectable() const
  437. {
  438. if( m_Layer == LAYER_WIRE || m_Layer == LAYER_BUS )
  439. return true;
  440. return false;
  441. }
  442. bool SCH_LINE::CanConnect( const SCH_ITEM* aItem ) const
  443. {
  444. if( m_Layer == LAYER_WIRE )
  445. {
  446. switch( aItem->Type() )
  447. {
  448. case SCH_JUNCTION_T:
  449. case SCH_NO_CONNECT_T:
  450. case SCH_LABEL_T:
  451. case SCH_GLOBAL_LABEL_T:
  452. case SCH_HIER_LABEL_T:
  453. case SCH_BUS_WIRE_ENTRY_T:
  454. case SCH_COMPONENT_T:
  455. case SCH_SHEET_T:
  456. case SCH_SHEET_PIN_T:
  457. return true;
  458. default:
  459. break;
  460. }
  461. }
  462. else if( m_Layer == LAYER_BUS )
  463. {
  464. switch( aItem->Type() )
  465. {
  466. case SCH_JUNCTION_T:
  467. case SCH_LABEL_T:
  468. case SCH_GLOBAL_LABEL_T:
  469. case SCH_HIER_LABEL_T:
  470. case SCH_BUS_WIRE_ENTRY_T:
  471. case SCH_SHEET_T:
  472. case SCH_SHEET_PIN_T:
  473. return true;
  474. default:
  475. break;
  476. }
  477. }
  478. return aItem->GetLayer() == m_Layer;
  479. }
  480. std::vector<wxPoint> SCH_LINE::GetConnectionPoints() const
  481. {
  482. return { m_start, m_end };
  483. }
  484. void SCH_LINE::GetSelectedPoints( std::vector< wxPoint >& aPoints ) const
  485. {
  486. if( m_Flags & STARTPOINT )
  487. aPoints.push_back( m_start );
  488. if( m_Flags & ENDPOINT )
  489. aPoints.push_back( m_end );
  490. }
  491. wxString SCH_LINE::GetSelectMenuText( EDA_UNITS aUnits ) const
  492. {
  493. wxString txtfmt, orient;
  494. if( m_start.x == m_end.x )
  495. {
  496. switch( m_Layer )
  497. {
  498. case LAYER_WIRE: txtfmt = _( "Vertical Wire, length %s" ); break;
  499. case LAYER_BUS: txtfmt = _( "Vertical Bus, length %s" ); break;
  500. default: txtfmt = _( "Vertical Graphic Line, length %s" ); break;
  501. }
  502. }
  503. else if( m_start.y == m_end.y )
  504. {
  505. switch( m_Layer )
  506. {
  507. case LAYER_WIRE: txtfmt = _( "Horizontal Wire, length %s" ); break;
  508. case LAYER_BUS: txtfmt = _( "Horizontal Bus, length %s" ); break;
  509. default: txtfmt = _( "Horizontal Graphic Line, length %s" ); break;
  510. }
  511. }
  512. else
  513. {
  514. switch( m_Layer )
  515. {
  516. case LAYER_WIRE: txtfmt = _( "Wire, length %s" ); break;
  517. case LAYER_BUS: txtfmt = _( "Bus, length %s" ); break;
  518. default: txtfmt = _( "Graphic Line, length %s" ); break;
  519. }
  520. }
  521. return wxString::Format( txtfmt,
  522. MessageTextFromValue( aUnits, EuclideanNorm( m_start - m_end ) ) );
  523. }
  524. BITMAP_DEF SCH_LINE::GetMenuImage() const
  525. {
  526. if( m_Layer == LAYER_NOTES )
  527. return add_dashed_line_xpm;
  528. else if( m_Layer == LAYER_WIRE )
  529. return add_line_xpm;
  530. return add_bus_xpm;
  531. }
  532. bool SCH_LINE::operator <( const SCH_ITEM& aItem ) const
  533. {
  534. if( Type() != aItem.Type() )
  535. return Type() < aItem.Type();
  536. auto line = static_cast<const SCH_LINE*>( &aItem );
  537. if( GetLayer() != line->GetLayer() )
  538. return GetLayer() < line->GetLayer();
  539. if( GetStartPoint().x != line->GetStartPoint().x )
  540. return GetStartPoint().x < line->GetStartPoint().x;
  541. if( GetStartPoint().y != line->GetStartPoint().y )
  542. return GetStartPoint().y < line->GetStartPoint().y;
  543. if( GetEndPoint().x != line->GetEndPoint().x )
  544. return GetEndPoint().x < line->GetEndPoint().x;
  545. return GetEndPoint().y < line->GetEndPoint().y;
  546. }
  547. bool SCH_LINE::HitTest( const wxPoint& aPosition, int aAccuracy ) const
  548. {
  549. // Performance enhancement for connection-building
  550. if( aPosition == m_start || aPosition == m_end )
  551. return true;
  552. // Insure minimum accuracy
  553. if( aAccuracy == 0 )
  554. aAccuracy = ( GetPenWidth() / 2 ) + 4;
  555. return TestSegmentHit( aPosition, m_start, m_end, aAccuracy );
  556. }
  557. bool SCH_LINE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
  558. {
  559. if( m_Flags & ( STRUCT_DELETED | SKIP_STRUCT ) )
  560. return false;
  561. EDA_RECT rect = aRect;
  562. if ( aAccuracy )
  563. rect.Inflate( aAccuracy );
  564. if( aContained )
  565. return rect.Contains( m_start ) && rect.Contains( m_end );
  566. return rect.Intersects( m_start, m_end );
  567. }
  568. void SCH_LINE::SwapData( SCH_ITEM* aItem )
  569. {
  570. SCH_LINE* item = (SCH_LINE*) aItem;
  571. std::swap( m_Layer, item->m_Layer );
  572. std::swap( m_start, item->m_start );
  573. std::swap( m_end, item->m_end );
  574. std::swap( m_startIsDangling, item->m_startIsDangling );
  575. std::swap( m_endIsDangling, item->m_endIsDangling );
  576. std::swap( m_stroke, item->m_stroke );
  577. }
  578. bool SCH_LINE::doIsConnected( const wxPoint& aPosition ) const
  579. {
  580. if( m_Layer != LAYER_WIRE && m_Layer != LAYER_BUS )
  581. return false;
  582. return IsEndPoint( aPosition );
  583. }
  584. void SCH_LINE::Plot( PLOTTER* aPlotter )
  585. {
  586. auto* settings = static_cast<KIGFX::SCH_RENDER_SETTINGS*>( aPlotter->RenderSettings() );
  587. int penWidth;
  588. COLOR4D color = GetLineColor();
  589. if( color == COLOR4D::UNSPECIFIED )
  590. color = settings->GetLayerColor( GetLayer() );
  591. aPlotter->SetColor( color );
  592. switch( m_Layer )
  593. {
  594. case LAYER_WIRE: penWidth = settings->m_DefaultWireThickness; break;
  595. case LAYER_BUS: penWidth = settings->m_DefaultBusThickness; break;
  596. default: penWidth = GetPenWidth(); break;
  597. }
  598. if( m_stroke.GetWidth() != 0 )
  599. penWidth = m_stroke.GetWidth();
  600. penWidth = std::max( penWidth, settings->GetMinPenWidth() );
  601. aPlotter->SetCurrentLineWidth( penWidth );
  602. aPlotter->SetDash( GetEffectiveLineStyle() );
  603. aPlotter->MoveTo( m_start );
  604. aPlotter->FinishTo( m_end );
  605. aPlotter->SetDash( PLOT_DASH_TYPE::SOLID );
  606. }
  607. void SCH_LINE::SetPosition( const wxPoint& aPosition )
  608. {
  609. m_end = m_end - ( m_start - aPosition );
  610. m_start = aPosition;
  611. }
  612. void SCH_LINE::GetMsgPanelInfo( EDA_DRAW_FRAME* aFrame, MSG_PANEL_ITEMS& aList )
  613. {
  614. wxString msg;
  615. switch( GetLayer() )
  616. {
  617. case LAYER_WIRE: msg = _( "Wire" ); break;
  618. case LAYER_BUS: msg = _( "Bus" ); break;
  619. default: msg = _( "Graphical" ); break;
  620. }
  621. aList.push_back( MSG_PANEL_ITEM( _( "Line Type" ), msg, DARKCYAN ) );
  622. if( GetLineStyle() != GetEffectiveLineStyle() )
  623. msg = _( "from netclass" );
  624. else
  625. msg = GetLineStyleName( GetLineStyle() );
  626. aList.push_back( MSG_PANEL_ITEM( _( "Line Style" ), msg, DARKCYAN ) );
  627. SCH_EDIT_FRAME* frame = dynamic_cast<SCH_EDIT_FRAME*>( aFrame );
  628. if( frame )
  629. {
  630. if( SCH_CONNECTION* conn = Connection( frame->GetCurrentSheet() ) )
  631. {
  632. conn->AppendInfoToMsgPanel( aList );
  633. NET_SETTINGS& netSettings = Schematic()->Prj().GetProjectFile().NetSettings();
  634. wxString netname = conn->Name();
  635. wxString netclassName = netSettings.m_NetClasses.GetDefaultPtr()->GetName();
  636. if( netSettings.m_NetClassAssignments.count( netname ) )
  637. netclassName = netSettings.m_NetClassAssignments[ netname ];
  638. aList.push_back( MSG_PANEL_ITEM( _( "Assigned Netclass" ), netclassName, DARKRED ) );
  639. }
  640. }
  641. }
  642. bool SCH_LINE::IsGraphicLine() const
  643. {
  644. return ( GetLayer() == LAYER_NOTES );
  645. }
  646. bool SCH_LINE::IsWire() const
  647. {
  648. return ( GetLayer() == LAYER_WIRE );
  649. }
  650. bool SCH_LINE::UsesDefaultStroke() const
  651. {
  652. return m_stroke.GetWidth() == 0 && m_stroke.GetColor() == COLOR4D::UNSPECIFIED
  653. && ( m_stroke.GetType() == GetDefaultStyle()
  654. || m_stroke.GetType() == PLOT_DASH_TYPE::DEFAULT );
  655. }