mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 10:13:19 +02:00
ADDED: Realtime junction indicators
Adds potential junctions to the preview overlay while drawing wires or dragging. Also fixes an issue where junctions were created at old splits Fixes https://gitlab.com/kicad/code/kicad/-/issues/18206
This commit is contained in:
parent
563489d612
commit
1a7a97a496
@ -20,6 +20,10 @@
|
||||
#include "junction_helpers.h"
|
||||
|
||||
#include <sch_line.h>
|
||||
#include <sch_screen.h>
|
||||
#include <sch_junction.h>
|
||||
#include <sch_item.h>
|
||||
#include <trigo.h>
|
||||
|
||||
using namespace JUNCTION_HELPERS;
|
||||
|
||||
@ -42,10 +46,68 @@ POINT_INFO JUNCTION_HELPERS::AnalyzePoint( const EE_RTREE& aItems, const VECTOR2
|
||||
std::unordered_set<int> exitAngles[2];
|
||||
std::vector<const SCH_LINE*> midPointLines[2];
|
||||
|
||||
EE_RTREE filtered;
|
||||
std::list<std::unique_ptr<SCH_LINE>> mergedLines;
|
||||
|
||||
// Ignore items that are currently being moved or flagged to skip
|
||||
// and temporarily merge collinear wires before analyzing the point.
|
||||
for( SCH_ITEM* item : aItems.Overlapping( aPosition ) )
|
||||
{
|
||||
if( item->GetEditFlags() & ( SKIP_STRUCT | STRUCT_DELETED ) )
|
||||
continue;
|
||||
|
||||
if( item->Type() == SCH_LINE_T )
|
||||
{
|
||||
SCH_LINE* line = static_cast<SCH_LINE*>( item );
|
||||
|
||||
if( line->IsConnectable() )
|
||||
{
|
||||
mergedLines.emplace_back( new SCH_LINE( *line ) );
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if( item->Type() == SCH_JUNCTION_T
|
||||
|| item->Type() == SCH_BUS_WIRE_ENTRY_T
|
||||
|| item->Type() == SCH_SHEET_T
|
||||
|| item->Type() == SCH_SYMBOL_T )
|
||||
{
|
||||
filtered.insert( item );
|
||||
}
|
||||
}
|
||||
|
||||
if( mergedLines.size() + filtered.size() < 2 )
|
||||
return info;
|
||||
|
||||
// Merge collinear wire segments
|
||||
bool merged = false;
|
||||
|
||||
do
|
||||
{
|
||||
merged = false;
|
||||
|
||||
for( auto it_i = mergedLines.begin(); it_i != mergedLines.end() && !merged; ++it_i )
|
||||
{
|
||||
for( auto it_j = std::next( it_i ); it_j != mergedLines.end(); ++it_j )
|
||||
{
|
||||
if( auto* line = ( *it_i )->MergeOverlap( nullptr, it_j->get(), false ) )
|
||||
{
|
||||
it_i->reset( line );
|
||||
mergedLines.erase( it_j );
|
||||
merged = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while( merged );
|
||||
|
||||
for( const auto& line : mergedLines )
|
||||
filtered.insert( line.get() );
|
||||
|
||||
|
||||
// A pin at 90° still shouldn't match a line at 90° so just give pins unique numbers
|
||||
int uniqueAngle = 10000;
|
||||
|
||||
for( const SCH_ITEM* item : aItems.Overlapping( aPosition ) )
|
||||
for( const SCH_ITEM* item : filtered )
|
||||
{
|
||||
if( item->GetEditFlags() & STRUCT_DELETED )
|
||||
continue;
|
||||
@ -139,4 +201,73 @@ POINT_INFO JUNCTION_HELPERS::AnalyzePoint( const EE_RTREE& aItems, const VECTOR2
|
||||
info.isJunction = exitAngles[WIRES].size() >= 3 || exitAngles[BUSES].size() >= 3;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
std::vector<SCH_JUNCTION*> JUNCTION_HELPERS::PreviewJunctions( const SCH_SCREEN* aScreen,
|
||||
const std::vector<SCH_ITEM*>& aItems )
|
||||
{
|
||||
EE_RTREE combined;
|
||||
|
||||
// Existing items
|
||||
for( const SCH_ITEM* item : aScreen->Items() )
|
||||
{
|
||||
if( !item->IsConnectable() )
|
||||
continue;
|
||||
|
||||
combined.insert( const_cast<SCH_ITEM*>( item ) );
|
||||
}
|
||||
|
||||
// Temporary items
|
||||
for( SCH_ITEM* item : aItems )
|
||||
{
|
||||
if( !item || !item->IsConnectable() )
|
||||
continue;
|
||||
combined.insert( item );
|
||||
}
|
||||
|
||||
std::vector<VECTOR2I> connections = aScreen->GetConnections();
|
||||
std::vector<VECTOR2I> pts;
|
||||
|
||||
for( SCH_ITEM* item : aItems )
|
||||
{
|
||||
if( !item || !item->IsConnectable() )
|
||||
continue;
|
||||
|
||||
std::vector<VECTOR2I> new_pts = item->GetConnectionPoints();
|
||||
pts.insert( pts.end(), new_pts.begin(), new_pts.end() );
|
||||
|
||||
if( item->Type() == SCH_LINE_T )
|
||||
{
|
||||
SCH_LINE* line = static_cast<SCH_LINE*>( item );
|
||||
|
||||
for( const VECTOR2I& pt : connections )
|
||||
{
|
||||
if( IsPointOnSegment( line->GetStartPoint(), line->GetEndPoint(), pt ) )
|
||||
pts.push_back( pt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::sort( pts.begin(), pts.end(),
|
||||
[]( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
return a.x < b.x || ( a.x == b.x && a.y < b.y );
|
||||
} );
|
||||
|
||||
pts.erase( std::unique( pts.begin(), pts.end() ), pts.end() );
|
||||
|
||||
std::vector<SCH_JUNCTION*> jcts;
|
||||
|
||||
for( const VECTOR2I& pt : pts )
|
||||
{
|
||||
POINT_INFO info = AnalyzePoint( combined, pt, false );
|
||||
|
||||
if( info.isJunction && ( !info.hasBusEntry || info.hasBusEntryToMultipleWires ) )
|
||||
{
|
||||
jcts.push_back( new SCH_JUNCTION( pt ) );
|
||||
}
|
||||
}
|
||||
|
||||
return jcts;
|
||||
}
|
@ -48,4 +48,15 @@ struct POINT_INFO
|
||||
*/
|
||||
POINT_INFO AnalyzePoint( const EE_RTREE& aItem, const VECTOR2I& aPosition, bool aBreakCrossings );
|
||||
|
||||
/**
|
||||
* Determine the points where explicit junctions would be required if the given
|
||||
* temporary items were committed to the schematic.
|
||||
*
|
||||
* @param aScreen The schematic screen containing the existing items.
|
||||
* @param aItems Temporary items not yet added to the screen.
|
||||
* @return Locations of needed junctions represented as new SCH_JUNCTION items.
|
||||
*/
|
||||
std::vector<class SCH_JUNCTION*> PreviewJunctions( const class SCH_SCREEN* aScreen,
|
||||
const std::vector<class SCH_ITEM*>& aItems );
|
||||
|
||||
} // namespace JUNCTION_HELPERS
|
||||
|
@ -62,6 +62,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <math/vector3.h>
|
||||
#include <memory>
|
||||
|
||||
// TODO(JE) Debugging only
|
||||
#include <core/profile.h>
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <sch_bus_entry.h>
|
||||
#include <sch_connection.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <sch_junction.h>
|
||||
#include <sch_line.h>
|
||||
#include <sch_screen.h>
|
||||
#include <sch_sheet.h>
|
||||
@ -58,6 +59,7 @@
|
||||
#include <schematic.h>
|
||||
#include <sch_commit.h>
|
||||
#include <sch_actions.h>
|
||||
#include <junction_helpers.h>
|
||||
#include <ee_grid_helper.h>
|
||||
#include <sch_selection.h>
|
||||
#include <sch_selection_tool.h>
|
||||
@ -939,6 +941,23 @@ int SCH_LINE_WIRE_BUS_TOOL::doDrawSegments( const TOOL_EVENT& aTool, SCH_COMMIT&
|
||||
if( !wire->IsNull() )
|
||||
m_view->AddToPreview( wire->Clone() );
|
||||
}
|
||||
|
||||
std::vector<SCH_ITEM*> previewItems;
|
||||
|
||||
for( SCH_LINE* wire : m_wires )
|
||||
{
|
||||
if( !wire->IsNull() )
|
||||
previewItems.push_back( wire );
|
||||
}
|
||||
|
||||
if( m_busUnfold.entry )
|
||||
previewItems.push_back( m_busUnfold.entry );
|
||||
|
||||
for( SCH_JUNCTION* jct : JUNCTION_HELPERS::PreviewJunctions( m_frame->GetScreen(),
|
||||
previewItems ) )
|
||||
{
|
||||
m_view->AddToPreview( jct, true );
|
||||
}
|
||||
}
|
||||
else if( evt->IsAction( &SCH_ACTIONS::undoLastSegment )
|
||||
|| evt->IsAction( &ACTIONS::doDelete )
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include <sch_sheet_pin.h>
|
||||
#include <sch_line.h>
|
||||
#include <sch_junction.h>
|
||||
#include <junction_helpers.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <eeschema_id.h>
|
||||
#include <pgm_base.h>
|
||||
@ -621,6 +622,28 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
static_cast<SCH_ITEM*>( item )->UpdateDanglingState( endPointsByType, endPointsByPos );
|
||||
}
|
||||
|
||||
// Hide junctions connected to line endpoints that are not selected
|
||||
m_hiddenJunctions.clear();
|
||||
|
||||
for( EDA_ITEM* edaItem : selection )
|
||||
{
|
||||
if( edaItem->Type() != SCH_LINE_T )
|
||||
continue;
|
||||
|
||||
SCH_LINE* line = static_cast<SCH_LINE*>( edaItem );
|
||||
|
||||
for( const VECTOR2I& pt : line->GetConnectionPoints() )
|
||||
{
|
||||
SCH_JUNCTION* jct = static_cast<SCH_JUNCTION*>( m_frame->GetScreen()->GetItem( pt, 0, SCH_JUNCTION_T ) );
|
||||
|
||||
if( jct && !jct->IsSelected()
|
||||
&& std::find( m_hiddenJunctions.begin(), m_hiddenJunctions.end(), jct ) == m_hiddenJunctions.end() )
|
||||
{
|
||||
m_view->Hide( jct, true );
|
||||
m_hiddenJunctions.push_back( jct );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generic setup
|
||||
snapLayer = grid.GetSelectionGrid( selection );
|
||||
@ -743,8 +766,10 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
//------------------------------------------------------------------------
|
||||
// Follow the mouse
|
||||
//
|
||||
m_view->ClearPreview();
|
||||
|
||||
m_cursor = grid.BestSnapAnchor( controls->GetCursorPosition( false ),
|
||||
snapLayer, selection );
|
||||
snapLayer, selection );
|
||||
|
||||
VECTOR2I delta( m_cursor - prevPos );
|
||||
m_anchorPos = m_cursor;
|
||||
@ -829,6 +854,23 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
if( selection.HasReferencePoint() )
|
||||
selection.SetReferencePoint( selection.GetReferencePoint() + delta );
|
||||
|
||||
std::vector<SCH_ITEM*> previewItems;
|
||||
|
||||
for( EDA_ITEM* it : selection )
|
||||
previewItems.push_back( static_cast<SCH_ITEM*>( it ) );
|
||||
|
||||
for( SCH_LINE* line : m_newDragLines )
|
||||
previewItems.push_back( line );
|
||||
|
||||
for( SCH_LINE* line : m_changedDragLines )
|
||||
previewItems.push_back( line );
|
||||
|
||||
for( SCH_JUNCTION* jct : JUNCTION_HELPERS::PreviewJunctions( m_frame->GetScreen(),
|
||||
previewItems ) )
|
||||
{
|
||||
m_view->AddToPreview( jct, true );
|
||||
}
|
||||
|
||||
m_toolMgr->PostEvent( EVENTS::SelectedItemsMoved );
|
||||
}
|
||||
|
||||
@ -864,6 +906,8 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
|
||||
clearNewDragLines();
|
||||
|
||||
m_view->ClearPreview();
|
||||
|
||||
break;
|
||||
}
|
||||
//------------------------------------------------------------------------
|
||||
@ -1067,6 +1111,12 @@ bool SCH_MOVE_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, SCH_COMMIT* aComm
|
||||
m_dragAdditions.clear();
|
||||
m_lineConnectionCache.clear();
|
||||
m_moveInProgress = false;
|
||||
|
||||
for( SCH_JUNCTION* jct : m_hiddenJunctions )
|
||||
m_view->Hide( jct, false );
|
||||
|
||||
m_hiddenJunctions.clear();
|
||||
m_view->ClearPreview();
|
||||
m_frame->PopTool( aEvent );
|
||||
|
||||
return !restore_state;
|
||||
|
@ -31,6 +31,10 @@
|
||||
|
||||
class SCH_EDIT_FRAME;
|
||||
class SCH_SELECTION_TOOL;
|
||||
class SCH_LINE;
|
||||
class SCH_LABEL_BASE;
|
||||
class SCH_SHEET_PIN;
|
||||
class SCH_JUNCTION;
|
||||
|
||||
|
||||
struct SPECIAL_CASE_LABEL_INFO
|
||||
@ -102,6 +106,8 @@ private:
|
||||
std::unordered_set<SCH_LINE*> m_newDragLines;
|
||||
///< Lines changed by drag algorithm that weren't selected
|
||||
std::unordered_set<SCH_LINE*> m_changedDragLines;
|
||||
///< Junctions that were hidden during the move
|
||||
std::vector<SCH_JUNCTION*> m_hiddenJunctions;
|
||||
|
||||
VECTOR2I m_moveOffset;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user