99                                             std::span<const PREVIEW_NET_ASSIGNMENT> aPreviewAssignments )
 
  101    wxLogTrace( 
traceSchDragNetCollision, 
"Update: Called with %zu junctions, %d selected items, %zu preview assignments",
 
  102                aJunctions.size(), aSelection.
GetSize(), aPreviewAssignments.size() );
 
  104    std::unordered_map<const SCH_ITEM*, std::optional<int>> previewNetCodes;
 
  106    previewNetCodes.reserve( aPreviewAssignments.size() );
 
  110        if( !assignment.item )
 
  115            assignment.netCode.has_value() ? std::to_string( *assignment.netCode ).c_str() : 
"none" );
 
  117        previewNetCodes[ assignment.item ] = assignment.netCode;
 
  120    std::vector<COLLISION_MARKER> markers;
 
  122    if( aJunctions.empty() )
 
  132            if( 
auto marker = 
analyzeJunction( junction, aSelection, previewNetCodes ) )
 
  135                            marker->position.x, marker->position.y );
 
  136                markers.push_back( *marker );
 
  143    if( markers.empty() && disconnections.empty() )
 
  152                markers.size(), disconnections.size() );
 
  157    COLOR4D baseColor( 1.0, 0.0, 0.0, 0.8 );
 
  164            baseColor = themeColor;
 
  167    double baseAlpha = baseColor.
a;
 
  169    if( baseAlpha <= 0.0 )
 
  172    double fillAlpha = std::clamp( baseAlpha * 0.35, 0.05, 1.0 );
 
  173    double strokeAlpha = std::clamp( baseAlpha, 0.05, 1.0 );
 
  180    int lineWidthPixels = 4;
 
  183        lineWidthPixels = std::max( cfg->m_Selection.drag_net_collision_width, 1 );
 
  185    double lineWidth = 
m_view->ToWorld( lineWidthPixels );
 
  187    if( lineWidth <= 0.0 )
 
  193        m_overlay->Circle( marker.position, marker.radius );
 
  197        m_overlay->Circle( marker.pointA, marker.radius );
 
  198        m_overlay->Circle( marker.pointB, marker.radius );
 
 
  253        const std::unordered_map<
const SCH_ITEM*, std::optional<int>>& aPreviewNetCodes )
 const 
  262                position.
x, position.
y );
 
  264    std::unordered_set<int> allNetCodes;
 
  265    std::unordered_set<int> movedNetCodes;
 
  266    std::unordered_set<int> originalNetCodes;
 
  267    std::unordered_set<int> movedOriginalNetCodes;
 
  268    std::unordered_set<int> stationaryOriginalNetCodes;
 
  270    auto accumulateNet = [&]( 
SCH_ITEM* item )
 
  278        if( !item->IsConnectable() )
 
  281                        item, item->GetClass().c_str() );
 
  285        if( !item->IsConnected( position ) && !( item->IsType( { SCH_LINE_T } ) && item->HitTest( position ) ) )
 
  288                        item, item->GetClass().c_str(), position.
x, position.
y );
 
  292        auto previewIt = aPreviewNetCodes.find( item );
 
  294        std::optional<int> netCodeOpt;
 
  295        std::optional<int> originalNetOpt;
 
  298            originalNetOpt = originalIt->second;
 
  300        if( previewIt != aPreviewNetCodes.end() )
 
  302            netCodeOpt = previewIt->second;
 
  304                        item, item->GetClass().c_str(),
 
  305                        netCodeOpt.has_value() ? std::to_string( *netCodeOpt ).c_str() : 
"none" );
 
  309            netCodeOpt = originalIt->second;
 
  311                        item, item->GetClass().c_str(),
 
  312                        netCodeOpt.has_value() ? std::to_string( *netCodeOpt ).c_str() : 
"none" );
 
  317                        item, item->GetClass().c_str() );
 
  320        bool isSelectionItem = item->IsSelected() || aSelection.
Contains( item );
 
  321        bool isMoved = ( previewIt != aPreviewNetCodes.end() ) || isSelectionItem;
 
  327                originalNetCodes.insert( *originalNetOpt );
 
  329                if( isSelectionItem )
 
  330                    movedOriginalNetCodes.insert( *originalNetOpt );
 
  332                    stationaryOriginalNetCodes.insert( *originalNetOpt );
 
  336                        item, item->GetClass().c_str() );
 
  340        int netCode = *netCodeOpt;
 
  341        allNetCodes.insert( netCode );
 
  344            item, item->GetClass().c_str(), netCode, isMoved ? 
"yes" : 
"no" );
 
  347            movedNetCodes.insert( netCode );
 
  351            originalNetCodes.insert( *originalNetOpt );
 
  353            if( isSelectionItem )
 
  354                movedOriginalNetCodes.insert( *originalNetOpt );
 
  356                stationaryOriginalNetCodes.insert( *originalNetOpt );
 
  362    int candidateCount = 0;
 
  367        accumulateNet( candidate );
 
  373    for( 
EDA_ITEM* selected : aSelection )
 
  374        accumulateNet( 
static_cast<SCH_ITEM*
>( selected ) );
 
  377                allNetCodes.size(), movedNetCodes.size() );
 
  379    if( !movedNetCodes.empty() )
 
  383        for( 
int netCode : movedNetCodes )
 
  388                "analyzeJunction: Original nets=%zu, moved originals=%zu, stationary originals=%zu",
 
  389                originalNetCodes.size(), movedOriginalNetCodes.size(), stationaryOriginalNetCodes.size() );
 
  391    if( !movedOriginalNetCodes.empty() )
 
  395        for( 
int netCode : movedOriginalNetCodes )
 
  399    if( !stationaryOriginalNetCodes.empty() )
 
  403        for( 
int netCode : stationaryOriginalNetCodes )
 
  407    if( allNetCodes.size() >= 2 )
 
  411        for( 
int netCode : allNetCodes )
 
  415    bool previewCollision = !movedNetCodes.empty() && allNetCodes.size() >= 2;
 
  417    bool originalCollision = 
false;
 
  419    if( !movedOriginalNetCodes.empty() && !stationaryOriginalNetCodes.empty() )
 
  421        for( 
int movedNet : movedOriginalNetCodes )
 
  423            for( 
int stationaryNet : stationaryOriginalNetCodes )
 
  425                if( movedNet != stationaryNet )
 
  427                    originalCollision = 
true;
 
  432            if( originalCollision )
 
  437    if( !previewCollision && !originalCollision )
 
  440                    movedNetCodes.size(), allNetCodes.size() );
 
  444    if( originalCollision && !previewCollision )
 
  447                        "analyzeJunction: Original net mismatch detected under moved endpoints" );
 
  453    marker.
radius = std::max( base * 1.5, 800.0 );
 
  456                position.
x, position.
y, marker.
radius );
 
 
  517    bool hasNewOrPastedItems = 
false;
 
  519    for( 
EDA_ITEM* edaItem : aSelection )
 
  521        if( edaItem->IsNew() || ( edaItem->GetFlags() & 
IS_PASTED ) )
 
  523            hasNewOrPastedItems = 
true;
 
  528    if( hasNewOrPastedItems )
 
  531                    "recordOriginalConnections: Skipping - selection contains new or pasted items" );
 
  537    for( 
EDA_ITEM* edaItem : aSelection )
 
  546        for( 
size_t index = 0; index < points.size(); ++index )
 
  548            const VECTOR2I& point = points[index];
 
  555                if( !candidate->CanConnect( item ) )
 
  558                if( !candidate->IsConnected( point )
 
  559                        && !( candidate->IsType( { SCH_LINE_T } ) && candidate->HitTest( point ) ) )
 
  564                std::vector<VECTOR2I> candidatePoints = candidate->GetConnectionPoints();
 
  565                size_t               candidateIndex = std::numeric_limits<size_t>::max();
 
  567                for( 
size_t candidatePos = 0; candidatePos < candidatePoints.size(); ++candidatePos )
 
  569                    if( candidatePoints[candidatePos] == point )
 
  571                        candidateIndex = candidatePos;
 
  576                if( candidateIndex == std::numeric_limits<size_t>::max() )
 
  580                size_t    firstIndex = index;
 
  582                size_t    secondIndex = candidateIndex;
 
  584                if( secondItem < firstItem || ( secondItem == firstItem && secondIndex < firstIndex ) )
 
  586                    std::swap( firstItem, secondItem );
 
  587                    std::swap( firstIndex, secondIndex );
 
  590                if( firstItem == secondItem )
 
  596                if( !firstSelected && !secondSelected )
 
  602                            return connection.itemA == firstItem && connection.indexA == firstIndex
 
  603                                   && connection.itemB == secondItem && connection.indexB == secondIndex;