mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-13 17:53:11 +02:00
Eeschema: Add option to show unconnected wire crossings as hop-overs.
This commit is contained in:
parent
b621e0ccf5
commit
f650999004
@ -312,6 +312,8 @@ ADVANCED_CFG::ADVANCED_CFG()
|
||||
|
||||
m_MaxPastedTextLength = 100;
|
||||
|
||||
m_hopOverArcRadius = 2.5;
|
||||
|
||||
loadFromConfigFile();
|
||||
}
|
||||
|
||||
|
@ -198,4 +198,25 @@ SCH_JUNCTION* SCH_EDIT_FRAME::AddJunction( SCH_COMMIT* aCommit, SCH_SCREEN* aScr
|
||||
return junction;
|
||||
}
|
||||
|
||||
void SCH_EDIT_FRAME::UpdateHopOveredWires( SCH_ITEM* aItem )
|
||||
{
|
||||
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> items;
|
||||
|
||||
GetCanvas()->GetView()->Query( aItem->GetBoundingBox(), items );
|
||||
|
||||
for( const auto& it : items )
|
||||
{
|
||||
if( !it.first->IsSCH_ITEM() )
|
||||
continue;
|
||||
|
||||
SCH_ITEM* item = static_cast<SCH_ITEM*>( it.first );
|
||||
|
||||
if( item == aItem )
|
||||
continue;
|
||||
|
||||
if( item->IsType( { SCH_ITEM_LOCATE_WIRE_T } ) )
|
||||
{
|
||||
GetCanvas()->GetView()->Update( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -463,6 +463,20 @@ void SCH_COMMIT::pushSchEdit( const wxString& aMessage, int aCommitFlags )
|
||||
|
||||
void SCH_COMMIT::Push( const wxString& aMessage, int aCommitFlags )
|
||||
{
|
||||
SCH_EDIT_FRAME* frame = static_cast<SCH_EDIT_FRAME*>( m_toolMgr->GetToolHolder() );
|
||||
|
||||
for( COMMIT_LINE& ent : m_changes )
|
||||
{
|
||||
SCH_ITEM* schCopyItem = dynamic_cast<SCH_ITEM*>( ent.m_copy );
|
||||
SCH_ITEM* schItem = dynamic_cast<SCH_ITEM*>( ent.m_item );
|
||||
|
||||
if( schCopyItem && schCopyItem->Type() == SCH_LINE_T )
|
||||
frame->UpdateHopOveredWires( schCopyItem );
|
||||
|
||||
if( schItem && schItem->Type() == SCH_LINE_T )
|
||||
frame->UpdateHopOveredWires( schItem );
|
||||
}
|
||||
|
||||
if( m_isLibEditor )
|
||||
pushLibEdit( aMessage, aCommitFlags );
|
||||
else
|
||||
|
@ -609,6 +609,8 @@ public:
|
||||
* @param aItem The junction to delete
|
||||
*/
|
||||
void DeleteJunction( SCH_COMMIT* aCommit, SCH_ITEM* aItem );
|
||||
|
||||
void UpdateHopOveredWires( SCH_ITEM* aItem );
|
||||
|
||||
void FlipBodyStyle( SCH_SYMBOL* aSymbol );
|
||||
|
||||
|
@ -1009,6 +1009,29 @@ double SCH_LINE::Similarity( const SCH_ITEM& aOther ) const
|
||||
}
|
||||
|
||||
|
||||
bool SCH_LINE::ShouldHopOver( const SCH_LINE* aLine ) const
|
||||
{
|
||||
bool isLine1Vertical = ( m_end.x == m_start.x );
|
||||
bool isLine2Vertical = ( aLine->GetEndPoint().x == aLine->GetStartPoint().x );
|
||||
|
||||
// Vertical vs. Horizontal: Horizontal should hop
|
||||
if( isLine1Vertical && !isLine2Vertical )
|
||||
return false;
|
||||
|
||||
if( isLine2Vertical && !isLine1Vertical )
|
||||
return true;
|
||||
|
||||
double slope1 = 0;
|
||||
double slope2 = 0;
|
||||
|
||||
slope1 = ( m_end.y - m_start.y ) / (double) ( m_end.x - m_start.x );
|
||||
slope2 = ( aLine->GetEndPoint().y - aLine->GetStartPoint().y )
|
||||
/ (double) ( aLine->GetEndPoint().x - aLine->GetStartPoint().x );
|
||||
|
||||
return fabs( slope1 ) < fabs( slope2 ); // The shallower line should hop
|
||||
}
|
||||
|
||||
|
||||
static struct SCH_LINE_DESC
|
||||
{
|
||||
SCH_LINE_DESC()
|
||||
|
@ -260,6 +260,8 @@ public:
|
||||
|
||||
bool IsParallel( const SCH_LINE* aLine ) const;
|
||||
|
||||
bool ShouldHopOver( const SCH_LINE* aLine ) const;
|
||||
|
||||
void GetEndPoints( std::vector<DANGLING_END_ITEM>& aItemList ) override;
|
||||
|
||||
bool UpdateDanglingState( std::vector<DANGLING_END_ITEM>& aItemListByType,
|
||||
|
@ -1480,23 +1480,140 @@ void SCH_PAINTER::draw( const SCH_LINE* aLine, int aLayer )
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetLineWidth( width );
|
||||
|
||||
if( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows )
|
||||
VECTOR2I currentLineStartPoint = aLine->GetStartPoint();
|
||||
VECTOR2I currentLineEndPoint = aLine->GetEndPoint();
|
||||
|
||||
std::vector<SCH_LINE*> existingLines;
|
||||
existingLines.clear();
|
||||
|
||||
if( aLine->IsWire() )
|
||||
{
|
||||
m_gal->DrawLine( aLine->GetStartPoint(), aLine->GetEndPoint() );
|
||||
SCH_SCREEN* curr_screen = m_schematic->GetCurrentScreen();
|
||||
|
||||
for( SCH_ITEM* item : curr_screen->Items().Overlapping( SCH_LINE_T, aLine->GetBoundingBox() ) )
|
||||
{
|
||||
SCH_LINE* line = static_cast<SCH_LINE*>( item );
|
||||
|
||||
if( line->IsWire() )
|
||||
existingLines.push_back( line );
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<VECTOR2I> intersections;
|
||||
|
||||
for( SCH_LINE* existingLine : existingLines )
|
||||
{
|
||||
VECTOR2I extLineStartPoint = existingLine->GetStartPoint();
|
||||
VECTOR2I extLineEndPoint = existingLine->GetEndPoint();
|
||||
|
||||
if( extLineStartPoint == currentLineStartPoint && extLineEndPoint == currentLineEndPoint )
|
||||
continue;
|
||||
|
||||
if( !aLine->ShouldHopOver( existingLine ) )
|
||||
continue;
|
||||
|
||||
SEG currentSegment = SEG( currentLineStartPoint, currentLineEndPoint );
|
||||
SEG existingSegment = SEG( extLineStartPoint, extLineEndPoint );
|
||||
|
||||
if( OPT_VECTOR2I intersect = currentSegment.Intersect( existingSegment, true, false ) )
|
||||
{
|
||||
if( aLine->IsEndPoint( *intersect ) || existingLine->IsEndPoint( *intersect ) )
|
||||
continue;
|
||||
|
||||
intersections.push_back( *intersect );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( intersections.empty() )
|
||||
{
|
||||
drawLine( currentLineStartPoint, currentLineEndPoint, lineStyle,
|
||||
( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows ), width );
|
||||
}
|
||||
else
|
||||
{
|
||||
SHAPE_SEGMENT line( aLine->GetStartPoint(), aLine->GetEndPoint() );
|
||||
auto getDistance = []( const VECTOR2I& a, const VECTOR2I& b ) -> double
|
||||
{
|
||||
return std::sqrt( std::pow( a.x - b.x, 2 ) + std::pow( a.y - b.y, 2 ) );
|
||||
};
|
||||
|
||||
STROKE_PARAMS::Stroke( &line, lineStyle, KiROUND( width ), &m_schSettings,
|
||||
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
// DrawLine has problem with 0 length lines so enforce minimum
|
||||
if( a == b )
|
||||
m_gal->DrawLine( a+1, b );
|
||||
else
|
||||
m_gal->DrawLine( a, b );
|
||||
} );
|
||||
std::sort( intersections.begin(), intersections.end(),
|
||||
[&]( const VECTOR2I& a, const VECTOR2I& b )
|
||||
{
|
||||
return getDistance( aLine->GetStartPoint(), a )
|
||||
< getDistance( aLine->GetStartPoint(), b );
|
||||
} );
|
||||
|
||||
VECTOR2I currentStart = aLine->GetStartPoint();
|
||||
float lineWidth = getLineWidth( aLine, drawingShadows, drawingNetColorHighlights );
|
||||
float arcRadius = lineWidth * ADVANCED_CFG::GetCfg().m_hopOverArcRadius;
|
||||
|
||||
for( const VECTOR2I& hopMid : intersections )
|
||||
{
|
||||
// Calculate the angle of the line from start point to end point in radians
|
||||
double lineAngle = std::atan2( aLine->GetEndPoint().y - aLine->GetStartPoint().y,
|
||||
aLine->GetEndPoint().x - aLine->GetStartPoint().x );
|
||||
|
||||
// Convert the angle from radians to degrees
|
||||
double lineAngleDeg = lineAngle * ( 180.0f / M_PI );
|
||||
|
||||
// Normalize the angle to be between 0 and 360 degrees
|
||||
if( lineAngleDeg < 0 )
|
||||
lineAngleDeg += 360;
|
||||
|
||||
double startAngle = lineAngleDeg;
|
||||
double endAngle = startAngle + 180.0f;
|
||||
|
||||
// Adjust the end angle if it exceeds 360 degrees
|
||||
if( endAngle >= 360.0 )
|
||||
endAngle -= 360.0;
|
||||
|
||||
// Convert start and end angles from degrees to radians
|
||||
double startAngleRad = startAngle * ( M_PI / 180.0f );
|
||||
double endAngleRad = endAngle * ( M_PI / 180.0f );
|
||||
|
||||
VECTOR2I arcStartPoint = {
|
||||
hopMid.x + static_cast<int>( arcRadius * cos( startAngleRad ) ),
|
||||
hopMid.y + static_cast<int>( arcRadius * sin( startAngleRad ) )
|
||||
};
|
||||
|
||||
VECTOR2I arcEndPoint = { hopMid.x + static_cast<int>( arcRadius * cos( endAngleRad ) ),
|
||||
hopMid.y
|
||||
+ static_cast<int>( arcRadius * sin( endAngleRad ) ) };
|
||||
|
||||
VECTOR2I arcMidPoint = {
|
||||
hopMid.x + static_cast<int>( arcRadius
|
||||
* cos( ( startAngleRad + endAngleRad ) / 2.0f ) ),
|
||||
hopMid.y + static_cast<int>( arcRadius
|
||||
* sin( ( startAngleRad + endAngleRad ) / 2.0f ) )
|
||||
};
|
||||
|
||||
VECTOR2I beforeHop = hopMid - VECTOR2I( arcRadius * std::cos( lineAngle ),
|
||||
arcRadius * std::sin( lineAngle ) );
|
||||
VECTOR2I afterHop = hopMid + VECTOR2I( arcRadius * std::cos( lineAngle ),
|
||||
arcRadius * std::sin( lineAngle ) );
|
||||
|
||||
// Draw the line from the current start point to the before-hop point
|
||||
drawLine( currentStart, beforeHop, lineStyle,
|
||||
( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows ), width );
|
||||
|
||||
// Create an arc object and draw it using the stroke function
|
||||
SHAPE_ARC arc( arcStartPoint, arcMidPoint, arcEndPoint, lineWidth );
|
||||
STROKE_PARAMS::Stroke( &arc, LINE_STYLE::DASH, KiROUND( width ), &m_schSettings,
|
||||
[&]( const VECTOR2I& start, const VECTOR2I& end )
|
||||
{
|
||||
if( start == end )
|
||||
m_gal->DrawLine( start + 1, end );
|
||||
else
|
||||
m_gal->DrawLine( start, end );
|
||||
} );
|
||||
|
||||
currentStart = afterHop;
|
||||
}
|
||||
|
||||
// Draw the final line from the current start point to the end point of the original line
|
||||
drawLine( currentStart, aLine->GetEndPoint(), lineStyle,
|
||||
( lineStyle <= LINE_STYLE::FIRST_TYPE || drawingShadows ), width );
|
||||
}
|
||||
}
|
||||
|
||||
@ -3112,4 +3229,26 @@ void SCH_PAINTER::draw( const SCH_GROUP* aGroup, int aLayer )
|
||||
}
|
||||
}
|
||||
|
||||
void SCH_PAINTER::drawLine( const VECTOR2I& aStartPoint, const VECTOR2I& aEndPoint,
|
||||
LINE_STYLE aLineStyle, bool aDrawDirectLine, int aWidth )
|
||||
{
|
||||
if( aDrawDirectLine )
|
||||
{
|
||||
m_gal->DrawLine( aStartPoint, aEndPoint );
|
||||
}
|
||||
else
|
||||
{
|
||||
SHAPE_SEGMENT segment( aStartPoint, aEndPoint );
|
||||
|
||||
STROKE_PARAMS::Stroke( &segment, aLineStyle, KiROUND( aWidth ), &m_schSettings,
|
||||
[&]( const VECTOR2I& start, const VECTOR2I& end )
|
||||
{
|
||||
if( start == end )
|
||||
m_gal->DrawLine( start + 1, end );
|
||||
else
|
||||
m_gal->DrawLine( start, end );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
}; // namespace KIGFX
|
||||
|
@ -140,6 +140,9 @@ private:
|
||||
|
||||
wxString expandLibItemTextVars( const wxString& aSourceText, const SCH_SYMBOL* aSymbolContext );
|
||||
|
||||
void drawLine( const VECTOR2I& aStartPoint, const VECTOR2I& aEndPoint, LINE_STYLE aLineStyle,
|
||||
bool aDrawDirectLine = false, int aWidth = 0 );
|
||||
|
||||
public:
|
||||
static std::vector<KICAD_T> g_ScaledSelectionTypes;
|
||||
|
||||
|
@ -813,7 +813,7 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( head && head->IsMoving() )
|
||||
moving = true;
|
||||
|
||||
|
||||
if( principalItemCount == 1 )
|
||||
{
|
||||
if( moving && selection.HasReferencePoint() )
|
||||
@ -993,7 +993,7 @@ int SCH_EDIT_TOOL::Rotate( const TOOL_EVENT& aEvent )
|
||||
|
||||
if( item->Type() == SCH_LINE_T )
|
||||
{
|
||||
SCH_LINE* line = (SCH_LINE*) item;
|
||||
SCH_LINE* line = (SCH_LINE*) item;
|
||||
|
||||
line->Rotate( rotPoint, !clockwise );
|
||||
}
|
||||
|
@ -713,6 +713,15 @@ public:
|
||||
*/
|
||||
double m_MinimumMarkerSeparationDistance;
|
||||
|
||||
/**
|
||||
* Default value for the Hop-Over Arc Radius, used to calculate the arc radius by multiplying
|
||||
* the line width when drawing a hop-over in scenarios where a wire crosses another.
|
||||
*
|
||||
* Setting name: "HopOverArcRadius"
|
||||
* Default value: 2.5
|
||||
*/
|
||||
double m_hopOverArcRadius;
|
||||
|
||||
/**
|
||||
* When updating the net inspector, it either recalculates all nets or iterates through items
|
||||
* one-by-one. This value controls the threshold at which all nets are recalculated rather than
|
||||
|
Loading…
x
Reference in New Issue
Block a user