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.

746 lines
20 KiB

2 years ago
2 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2006 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
  5. * Copyright The 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 <pgm_base.h>
  25. #include <settings/settings_manager.h>
  26. #include <eeschema_settings.h>
  27. #include <eda_item.h>
  28. #include <sch_connection.h>
  29. #include <sch_group.h>
  30. #include <sch_rule_area.h>
  31. #include <sch_draw_panel.h>
  32. #include <sch_edit_frame.h>
  33. #include <connection_graph.h>
  34. #include <netclass.h>
  35. #include <project/project_file.h>
  36. #include <project/net_settings.h>
  37. #include <font/kicad_font_name.h>
  38. // Rendering fonts is expensive (particularly when using outline fonts). At small effective
  39. // sizes (ie: zoomed out) the visual differences between outline and/or stroke fonts and the
  40. // bitmap font becomes immaterial, and there's often more to draw when zoomed out so the
  41. // performance gain becomes more significant.
  42. #define BITMAP_FONT_SIZE_THRESHOLD 3
  43. wxString SCH_ITEM::GetUnitDescription( int aUnit )
  44. {
  45. if( aUnit == 0 )
  46. return _( "All" );
  47. else
  48. return LIB_SYMBOL::LetterSubReference( aUnit, 'A' );
  49. }
  50. wxString SCH_ITEM::GetBodyStyleDescription( int aBodyStyle )
  51. {
  52. if( aBodyStyle == 0 )
  53. return _( "All" );
  54. else if( aBodyStyle == BODY_STYLE::DEMORGAN )
  55. return _( "Alternate" );
  56. else if( aBodyStyle == BODY_STYLE::BASE )
  57. return _( "Standard" );
  58. else
  59. return wxT( "?" );
  60. }
  61. /* Constructor and destructor for SCH_ITEM */
  62. /* They are not inline because this creates problems with gcc at linking time in debug mode */
  63. SCH_ITEM::SCH_ITEM( EDA_ITEM* aParent, KICAD_T aType, int aUnit, int aBodyStyle ) :
  64. EDA_ITEM( aParent, aType, true, false ),
  65. m_unit( aUnit ),
  66. m_bodyStyle( aBodyStyle ),
  67. m_private( false )
  68. {
  69. m_layer = LAYER_WIRE; // It's only a default, in fact
  70. m_fieldsAutoplaced = AUTOPLACE_NONE;
  71. m_connectivity_dirty = false; // Item is unconnected until it is placed, so it's clean
  72. }
  73. SCH_ITEM::SCH_ITEM( const SCH_ITEM& aItem ) :
  74. EDA_ITEM( aItem )
  75. {
  76. m_layer = aItem.m_layer;
  77. m_unit = aItem.m_unit;
  78. m_bodyStyle = aItem.m_bodyStyle;
  79. m_private = aItem.m_private;
  80. m_fieldsAutoplaced = aItem.m_fieldsAutoplaced;
  81. m_connectivity_dirty = aItem.m_connectivity_dirty;
  82. }
  83. SCH_ITEM& SCH_ITEM::operator=( const SCH_ITEM& aItem )
  84. {
  85. m_layer = aItem.m_layer;
  86. m_unit = aItem.m_unit;
  87. m_bodyStyle = aItem.m_bodyStyle;
  88. m_private = aItem.m_private;
  89. m_fieldsAutoplaced = aItem.m_fieldsAutoplaced;
  90. m_connectivity_dirty = aItem.m_connectivity_dirty;
  91. return *this;
  92. }
  93. SCH_ITEM::~SCH_ITEM()
  94. {
  95. for( const auto& it : m_connection_map )
  96. delete it.second;
  97. // Do not try to modify SCHEMATIC::ConnectionGraph()
  98. // if the schematic does not exist
  99. if( !SCHEMATIC::m_IsSchematicExists )
  100. return;
  101. SCHEMATIC* sch = Schematic();
  102. if( sch != nullptr )
  103. sch->ConnectionGraph()->RemoveItem( this );
  104. }
  105. bool SCH_ITEM::IsGroupableType() const
  106. {
  107. switch( Type() )
  108. {
  109. case SCH_SYMBOL_T:
  110. case SCH_PIN_T:
  111. case SCH_SHAPE_T:
  112. case SCH_BITMAP_T:
  113. case SCH_FIELD_T:
  114. case SCH_TEXT_T:
  115. case SCH_TEXTBOX_T:
  116. case SCH_TABLE_T:
  117. case SCH_GROUP_T:
  118. case SCH_LINE_T:
  119. case SCH_JUNCTION_T:
  120. case SCH_NO_CONNECT_T:
  121. case SCH_BUS_WIRE_ENTRY_T:
  122. case SCH_BUS_BUS_ENTRY_T:
  123. case SCH_LABEL_T:
  124. case SCH_GLOBAL_LABEL_T:
  125. case SCH_HIER_LABEL_T:
  126. case SCH_RULE_AREA_T:
  127. case SCH_DIRECTIVE_LABEL_T:
  128. case SCH_SHEET_PIN_T:
  129. case SCH_SHEET_T:
  130. return true;
  131. default:
  132. return false;
  133. }
  134. }
  135. SCH_ITEM* SCH_ITEM::Duplicate( bool addToParentGroup, SCH_COMMIT* aCommit, bool doClone ) const
  136. {
  137. SCH_ITEM* newItem = (SCH_ITEM*) Clone();
  138. if( !doClone )
  139. const_cast<KIID&>( newItem->m_Uuid ) = KIID();
  140. newItem->ClearFlags( SELECTED | BRIGHTENED );
  141. newItem->RunOnChildren(
  142. []( SCH_ITEM* aChild )
  143. {
  144. aChild->ClearFlags( SELECTED | BRIGHTENED );
  145. },
  146. RECURSE_MODE::NO_RECURSE );
  147. if( addToParentGroup )
  148. {
  149. wxCHECK_MSG( aCommit, newItem, "Must supply a commit to update parent group" );
  150. if( EDA_GROUP* group = newItem->GetParentGroup() )
  151. {
  152. aCommit->Modify( group->AsEdaItem(), nullptr, RECURSE_MODE::NO_RECURSE );
  153. group->AddItem( newItem );
  154. }
  155. }
  156. return newItem;
  157. }
  158. void SCH_ITEM::SetUnitProp( int aUnit )
  159. {
  160. if( GetParentSymbol() )
  161. aUnit = std::min( aUnit, GetParentSymbol()->GetUnitCount() );
  162. aUnit = std::max( aUnit, 0 );
  163. m_unit = aUnit;
  164. }
  165. void SCH_ITEM::SetBodyStyleProp( int aBodyStyle )
  166. {
  167. if( GetParentSymbol() && GetParentSymbol()->HasAlternateBodyStyle() )
  168. aBodyStyle = std::min( aBodyStyle, (int) BODY_STYLE::DEMORGAN );
  169. aBodyStyle = std::max( aBodyStyle, 0 );
  170. m_bodyStyle = aBodyStyle;
  171. }
  172. SCHEMATIC* SCH_ITEM::Schematic() const
  173. {
  174. return static_cast<SCHEMATIC*>( findParent( SCHEMATIC_T ) );
  175. }
  176. const SYMBOL* SCH_ITEM::GetParentSymbol() const
  177. {
  178. if( SYMBOL* sch_symbol = static_cast<SCH_SYMBOL*>( findParent( SCH_SYMBOL_T ) ) )
  179. return sch_symbol;
  180. if( SYMBOL* lib_symbol = static_cast<LIB_SYMBOL*>( findParent( LIB_SYMBOL_T ) ) )
  181. return lib_symbol;
  182. return nullptr;
  183. }
  184. SYMBOL* SCH_ITEM::GetParentSymbol()
  185. {
  186. if( SYMBOL* sch_symbol = static_cast<SCH_SYMBOL*>( findParent( SCH_SYMBOL_T ) ) )
  187. return sch_symbol;
  188. if( SYMBOL* lib_symbol = static_cast<LIB_SYMBOL*>( findParent( LIB_SYMBOL_T ) ) )
  189. return lib_symbol;
  190. return nullptr;
  191. }
  192. bool SCH_ITEM::ResolveExcludedFromSim() const
  193. {
  194. if( GetExcludedFromSim() )
  195. return true;
  196. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  197. {
  198. if( area->GetExcludedFromSim() )
  199. return true;
  200. }
  201. return false;
  202. }
  203. bool SCH_ITEM::ResolveExcludedFromBOM() const
  204. {
  205. if( GetExcludedFromBOM() )
  206. return true;
  207. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  208. {
  209. if( area->GetExcludedFromBOM() )
  210. return true;
  211. }
  212. return false;
  213. }
  214. bool SCH_ITEM::ResolveExcludedFromBoard() const
  215. {
  216. if( GetExcludedFromBoard() )
  217. return true;
  218. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  219. {
  220. if( area->GetExcludedFromBoard() )
  221. return true;
  222. }
  223. return false;
  224. }
  225. bool SCH_ITEM::ResolveDNP() const
  226. {
  227. if( GetDNP() )
  228. return true;
  229. for( SCH_RULE_AREA* area : m_rule_areas_cache )
  230. {
  231. if( area->GetDNP() )
  232. return true;
  233. }
  234. return false;
  235. }
  236. std::vector<int> SCH_ITEM::ViewGetLayers() const
  237. {
  238. // Basic fallback
  239. return { LAYER_DEVICE, LAYER_DEVICE_BACKGROUND, LAYER_SELECTION_SHADOWS };
  240. }
  241. bool SCH_ITEM::IsConnected( const VECTOR2I& aPosition ) const
  242. {
  243. if(( m_flags & STRUCT_DELETED ) || ( m_flags & SKIP_STRUCT ) )
  244. return false;
  245. return doIsConnected( aPosition );
  246. }
  247. SCH_CONNECTION* SCH_ITEM::Connection( const SCH_SHEET_PATH* aSheet ) const
  248. {
  249. if( !IsConnectable() )
  250. return nullptr;
  251. if( !aSheet )
  252. aSheet = &Schematic()->CurrentSheet();
  253. auto it = m_connection_map.find( *aSheet );
  254. if( it == m_connection_map.end() )
  255. return nullptr;
  256. else
  257. return it->second;
  258. }
  259. void SCH_ITEM::SetConnectionGraph( CONNECTION_GRAPH* aGraph )
  260. {
  261. for( auto& [path, conn] : m_connection_map )
  262. {
  263. conn->SetGraph( aGraph );
  264. for( auto& member : conn->AllMembers() )
  265. member->SetGraph( aGraph );
  266. }
  267. }
  268. std::shared_ptr<NETCLASS> SCH_ITEM::GetEffectiveNetClass( const SCH_SHEET_PATH* aSheet ) const
  269. {
  270. static std::shared_ptr<NETCLASS> nullNetclass = std::make_shared<NETCLASS>( wxEmptyString );
  271. SCHEMATIC* schematic = Schematic();
  272. if( schematic )
  273. {
  274. std::shared_ptr<NET_SETTINGS>& netSettings =
  275. schematic->Prj().GetProjectFile().m_NetSettings;
  276. SCH_CONNECTION* connection = Connection( aSheet );
  277. if( connection )
  278. return netSettings->GetEffectiveNetClass( connection->Name() );
  279. else
  280. return netSettings->GetDefaultNetclass();
  281. }
  282. return nullNetclass;
  283. }
  284. void SCH_ITEM::ClearConnectedItems( const SCH_SHEET_PATH& aSheet )
  285. {
  286. auto it = m_connected_items.find( aSheet );
  287. if( it != m_connected_items.end() )
  288. it->second.clear();
  289. }
  290. const SCH_ITEM_VEC& SCH_ITEM::ConnectedItems( const SCH_SHEET_PATH& aSheet )
  291. {
  292. return m_connected_items[ aSheet ];
  293. }
  294. void SCH_ITEM::AddConnectionTo( const SCH_SHEET_PATH& aSheet, SCH_ITEM* aItem )
  295. {
  296. SCH_ITEM_VEC& vec = m_connected_items[ aSheet ];
  297. // The vector elements are small, so reserve 1k at a time to prevent re-allocations
  298. if( vec.size() == vec.capacity() )
  299. vec.reserve( vec.size() + 4096 );
  300. // Add item to the correct place in the sorted vector if it is not already there
  301. auto it = std::lower_bound( vec.begin(), vec.end(), aItem );
  302. if( it == vec.end() || *it != aItem )
  303. vec.insert( it, aItem );
  304. }
  305. SCH_CONNECTION* SCH_ITEM::InitializeConnection( const SCH_SHEET_PATH& aSheet,
  306. CONNECTION_GRAPH* aGraph )
  307. {
  308. SCH_CONNECTION* connection = Connection( &aSheet );
  309. // N.B. Do not clear the dirty connectivity flag here because we may need
  310. // to create a connection for a different sheet, and we don't want to
  311. // skip the connection creation because the flag is cleared.
  312. if( connection )
  313. {
  314. connection->Reset();
  315. }
  316. else
  317. {
  318. connection = new SCH_CONNECTION( this );
  319. m_connection_map.insert( std::make_pair( aSheet, connection ) );
  320. }
  321. connection->SetGraph( aGraph );
  322. connection->SetSheet( aSheet );
  323. return connection;
  324. }
  325. SCH_CONNECTION* SCH_ITEM::GetOrInitConnection( const SCH_SHEET_PATH& aSheet,
  326. CONNECTION_GRAPH* aGraph )
  327. {
  328. if( !IsConnectable() )
  329. return nullptr;
  330. SCH_CONNECTION* connection = Connection( &aSheet );
  331. if( connection )
  332. return connection;
  333. else
  334. return InitializeConnection( aSheet, aGraph );
  335. }
  336. const wxString& SCH_ITEM::GetCachedDriverName() const
  337. {
  338. static wxString s_empty;
  339. return s_empty;
  340. }
  341. void SCH_ITEM::swapData( SCH_ITEM* aItem )
  342. {
  343. UNIMPLEMENTED_FOR( GetClass() );
  344. }
  345. void SCH_ITEM::SwapItemData( SCH_ITEM* aImage )
  346. {
  347. if( aImage == nullptr )
  348. return;
  349. EDA_ITEM* parent = GetParent();
  350. SwapFlags( aImage );
  351. std::swap( m_group, aImage->m_group );
  352. swapData( aImage );
  353. SetParent( parent );
  354. }
  355. void SCH_ITEM::SwapFlags( SCH_ITEM* aItem )
  356. {
  357. EDA_ITEM_FLAGS editFlags = GetEditFlags();
  358. EDA_ITEM_FLAGS tempFlags = GetTempFlags();
  359. EDA_ITEM_FLAGS aItem_editFlags = aItem->GetEditFlags();
  360. EDA_ITEM_FLAGS aItem_tempFlags = aItem->GetTempFlags();
  361. std::swap( m_flags, aItem->m_flags );
  362. ClearEditFlags();
  363. SetFlags( editFlags );
  364. ClearTempFlags();
  365. SetFlags( tempFlags );
  366. aItem->ClearEditFlags();
  367. aItem->SetFlags( aItem_editFlags );
  368. aItem->ClearTempFlags();
  369. aItem->SetFlags( aItem_tempFlags );
  370. }
  371. void SCH_ITEM::ClearCaches()
  372. {
  373. auto clearTextCaches =
  374. []( SCH_ITEM* aItem )
  375. {
  376. EDA_TEXT* text = dynamic_cast<EDA_TEXT*>( aItem );
  377. if( text )
  378. {
  379. text->ClearBoundingBoxCache();
  380. text->ClearRenderCache();
  381. }
  382. };
  383. clearTextCaches( this );
  384. RunOnChildren( clearTextCaches, RECURSE_MODE::NO_RECURSE );
  385. }
  386. bool SCH_ITEM::operator==( const SCH_ITEM& aOther ) const
  387. {
  388. if( Type() != aOther.Type() )
  389. return false;
  390. return compare( aOther, SCH_ITEM::COMPARE_FLAGS::EQUALITY ) == 0;
  391. }
  392. bool SCH_ITEM::operator<( const SCH_ITEM& aOther ) const
  393. {
  394. if( Type() != aOther.Type() )
  395. return Type() < aOther.Type();
  396. return ( compare( aOther ) < 0 );
  397. }
  398. bool SCH_ITEM::cmp_items::operator()( const SCH_ITEM* aFirst, const SCH_ITEM* aSecond ) const
  399. {
  400. return aFirst->compare( *aSecond, COMPARE_FLAGS::EQUALITY ) < 0;
  401. }
  402. int SCH_ITEM::compare( const SCH_ITEM& aOther, int aCompareFlags ) const
  403. {
  404. if( Type() != aOther.Type() )
  405. return Type() - aOther.Type();
  406. if( !( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::UNIT ) && m_unit != aOther.m_unit )
  407. return m_unit - aOther.m_unit;
  408. if( !( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::UNIT ) && m_bodyStyle != aOther.m_bodyStyle )
  409. return m_bodyStyle - aOther.m_bodyStyle;
  410. if( IsPrivate() != aOther.IsPrivate() )
  411. return IsPrivate() ? 1 : -1;
  412. if( !( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::SKIP_TST_POS ) )
  413. {
  414. if( GetPosition().x != aOther.GetPosition().x )
  415. return GetPosition().x - aOther.GetPosition().x;
  416. if( GetPosition().y != aOther.GetPosition().y )
  417. return GetPosition().y - aOther.GetPosition().y;
  418. }
  419. if( ( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::EQUALITY )
  420. || ( aCompareFlags & SCH_ITEM::COMPARE_FLAGS::ERC ) )
  421. {
  422. return 0;
  423. }
  424. if( m_Uuid < aOther.m_Uuid )
  425. return -1;
  426. if( m_Uuid > aOther.m_Uuid )
  427. return 1;
  428. return 0;
  429. }
  430. const wxString& SCH_ITEM::GetDefaultFont() const
  431. {
  432. static wxString defaultName = KICAD_FONT_NAME;
  433. EESCHEMA_SETTINGS* cfg = GetAppSettings<EESCHEMA_SETTINGS>( "eeschema" );
  434. return cfg ? cfg->m_Appearance.default_font : defaultName;
  435. }
  436. const KIFONT::METRICS& SCH_ITEM::GetFontMetrics() const
  437. {
  438. if( SCHEMATIC* schematic = Schematic() )
  439. return schematic->Settings().m_FontMetrics;
  440. return KIFONT::METRICS::Default();
  441. }
  442. int SCH_ITEM::GetEffectivePenWidth( const SCH_RENDER_SETTINGS* aSettings ) const
  443. {
  444. // For historical reasons, a stored value of 0 means "default width" and negative
  445. // numbers meant "don't stroke".
  446. if( GetPenWidth() < 0 )
  447. {
  448. return 0;
  449. }
  450. else if( GetPenWidth() == 0 )
  451. {
  452. if( GetParent() && GetParent()->Type() == LIB_SYMBOL_T )
  453. return std::max( aSettings->m_SymbolLineWidth, aSettings->GetMinPenWidth() );
  454. else
  455. return std::max( aSettings->GetDefaultPenWidth(), aSettings->GetMinPenWidth() );
  456. }
  457. else
  458. {
  459. return std::max( GetPenWidth(), aSettings->GetMinPenWidth() );
  460. }
  461. }
  462. bool SCH_ITEM::RenderAsBitmap( double aWorldScale ) const
  463. {
  464. if( IsHypertext() )
  465. return false;
  466. if( const EDA_TEXT* text = dynamic_cast<const EDA_TEXT*>( this ) )
  467. return text->GetTextHeight() * aWorldScale < BITMAP_FONT_SIZE_THRESHOLD;
  468. return false;
  469. }
  470. void SCH_ITEM::getSymbolEditorMsgPanelInfo( EDA_DRAW_FRAME* aFrame,
  471. std::vector<MSG_PANEL_ITEM>& aList )
  472. {
  473. aList.emplace_back( _( "Type" ), GetFriendlyName() );
  474. if( const SYMBOL* parent = GetParentSymbol() )
  475. {
  476. if( parent->GetUnitCount() )
  477. aList.emplace_back( _( "Unit" ), GetUnitDescription( m_unit ) );
  478. if( parent->HasAlternateBodyStyle() )
  479. aList.emplace_back( _( "Body Style" ), GetBodyStyleDescription( m_bodyStyle ) );
  480. }
  481. if( IsPrivate() )
  482. aList.emplace_back( _( "Private" ), wxEmptyString );
  483. }
  484. static struct SCH_ITEM_DESC
  485. {
  486. SCH_ITEM_DESC()
  487. {
  488. PROPERTY_MANAGER& propMgr = PROPERTY_MANAGER::Instance();
  489. REGISTER_TYPE( SCH_ITEM );
  490. propMgr.InheritsAfter( TYPE_HASH( SCH_ITEM ), TYPE_HASH( EDA_ITEM ) );
  491. #ifdef NOTYET
  492. // Not yet functional in UI
  493. propMgr.AddProperty( new PROPERTY<SCH_ITEM, bool>( _HKI( "Locked" ),
  494. &SCH_ITEM::SetLocked, &SCH_ITEM::IsLocked ) );
  495. #endif
  496. auto multiUnit =
  497. [=]( INSPECTABLE* aItem ) -> bool
  498. {
  499. if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( aItem ) )
  500. {
  501. if( const SYMBOL* symbol = schItem->GetParentSymbol() )
  502. return symbol->IsMulti();
  503. }
  504. return false;
  505. };
  506. auto multiBodyStyle =
  507. [=]( INSPECTABLE* aItem ) -> bool
  508. {
  509. if( SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( aItem ) )
  510. {
  511. if( const SYMBOL* symbol = schItem->GetParentSymbol() )
  512. return symbol->HasAlternateBodyStyle();
  513. }
  514. return false;
  515. };
  516. propMgr.AddProperty( new PROPERTY<SCH_ITEM, int>( _HKI( "Unit" ),
  517. &SCH_ITEM::SetUnitProp, &SCH_ITEM::GetUnit ) )
  518. .SetAvailableFunc( multiUnit )
  519. .SetIsHiddenFromDesignEditors();
  520. propMgr.AddProperty( new PROPERTY<SCH_ITEM, int>( _HKI( "Body Style" ),
  521. &SCH_ITEM::SetBodyStyle, &SCH_ITEM::GetBodyStyle ) )
  522. .SetAvailableFunc( multiBodyStyle )
  523. .SetIsHiddenFromDesignEditors();
  524. propMgr.AddProperty( new PROPERTY<SCH_ITEM, bool>( _HKI( "Private" ),
  525. &SCH_ITEM::SetPrivate, &SCH_ITEM::IsPrivate ) )
  526. .SetIsHiddenFromDesignEditors();
  527. }
  528. } _SCH_ITEM_DESC;
  529. IMPLEMENT_ENUM_TO_WXANY( SCH_LAYER_ID )
  530. static bool lessYX( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
  531. {
  532. const auto aPos = a.GetPosition();
  533. const auto bPos = b.GetPosition();
  534. return aPos.y < bPos.y ? true : ( aPos.y > bPos.y ? false : aPos.x < bPos.x );
  535. };
  536. static bool lessType( const DANGLING_END_ITEM& a, const DANGLING_END_ITEM& b )
  537. {
  538. return a.GetType() < b.GetType();
  539. };
  540. std::vector<DANGLING_END_ITEM>::iterator
  541. DANGLING_END_ITEM_HELPER::get_lower_pos( std::vector<DANGLING_END_ITEM>& aItemListByPos,
  542. const VECTOR2I& aPos )
  543. {
  544. DANGLING_END_ITEM needle = DANGLING_END_ITEM( PIN_END, nullptr, aPos );
  545. auto start = aItemListByPos.begin();
  546. auto end = aItemListByPos.end();
  547. return std::lower_bound( start, end, needle, lessYX );
  548. }
  549. std::vector<DANGLING_END_ITEM>::iterator
  550. DANGLING_END_ITEM_HELPER::get_lower_type( std::vector<DANGLING_END_ITEM>& aItemListByType,
  551. const DANGLING_END_T& aType )
  552. {
  553. DANGLING_END_ITEM needle = DANGLING_END_ITEM( aType, nullptr, VECTOR2I{} );
  554. auto start = aItemListByType.begin();
  555. auto end = aItemListByType.end();
  556. return std::lower_bound( start, end, needle, lessType );
  557. }
  558. void DANGLING_END_ITEM_HELPER::sort_dangling_end_items(
  559. std::vector<DANGLING_END_ITEM>& aItemListByType,
  560. std::vector<DANGLING_END_ITEM>& aItemListByPos )
  561. {
  562. // WIRE_END pairs must be kept together. Hence stable sort.
  563. std::stable_sort( aItemListByType.begin(), aItemListByType.end(), lessType );
  564. // Sort by y first, pins are more likely to share x than y.
  565. std::sort( aItemListByPos.begin(), aItemListByPos.end(), lessYX );
  566. }