Commit 073a9e17 authored by Lorenzo Marcantonio's avatar Lorenzo Marcantonio
Browse files

TRACK::GetTrack can now be told to confine search to the netlist and/or force...

TRACK::GetTrack can now be told to confine search to the netlist and/or force the sequential (restartable) algorithm
Reworked the collinear track routines. Cleanup should be faster given the above modification.
parent 41e41b95
Loading
Loading
Loading
Loading
+44 −112
Original line number Original line Diff line number Diff line
@@ -66,28 +66,6 @@ static bool ShowClearance( const TRACK* aTrack )
}
}




/*
 * return true if the dist between p1 and p2 < max_dist
 * Currently in test (currently ratsnest algos work only if p1 == p2)
 */
inline bool IsNear( const wxPoint& p1, const wxPoint& p2, int max_dist )
{
#if 0   // Do not change it: does not work
    int dist;
    dist = abs( p1.x - p2.x ) + abs( p1.y - p2.y );
    dist *= 7;
    dist /= 10;

    if ( dist < max_dist )
        return true;
#else
    if ( p1 == p2 )
        return true;
#endif
    return false;
}


TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace,
TRACK* GetTrack( TRACK* aStartTrace, const TRACK* aEndTrace,
        const wxPoint& aPosition, LAYER_MSK aLayerMask )
        const wxPoint& aPosition, LAYER_MSK aLayerMask )
{
{
@@ -1303,123 +1281,77 @@ VIA* TRACK::GetVia( TRACK* aEndTrace, const wxPoint& aPosition, LAYER_MSK aLayer
}
}




TRACK* TRACK::GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint )
TRACK* TRACK::GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint,
        bool aSameNetOnly, bool aSequential )
{
{
    const int NEIGHTBOUR_COUNT_MAX = 50;
    const wxPoint &position = GetEndPoint( aEndPoint );

    LAYER_MSK refLayers = GetLayerMask();
    TRACK *previousSegment;
    TRACK *previousSegment;
    TRACK *nextSegment;
    TRACK *nextSegment;
    int     Reflayer;
    int     ii;
    int     max_dist;
    const wxPoint &position = GetEndPoint( aEndPoint );


    Reflayer = GetLayerMask();
    if( aSequential )

    previousSegment = nextSegment = this;

    // Local search:
    for( ii = 0; ii < NEIGHTBOUR_COUNT_MAX; ii++ )
    {
    {
        if( (nextSegment == NULL) && (previousSegment == NULL) )
        // Simple sequential search: from aStartTrace forward to aEndTrace
            break;
        previousSegment = NULL;

        nextSegment = aStartTrace;
        if( nextSegment )
    }
    else
    {
    {
            if( nextSegment->GetState( BUSY | IS_DELETED ) )
        /* Local bidirectional search: from this backward to aStartTrace
                goto suite;
         * AND forward to aEndTrace. The idea is that nearest segments

         * are found (on average) faster in this way. In fact same-net
            if( nextSegment == this )
         * segments are almost guaranteed to be found faster, in a global
                goto suite;
         * search, since they are grouped together in the track list */

        previousSegment = this;
            /* max_dist is the max distance between 2 track ends which
        nextSegment = this;
             * ensure a copper continuity */
    }
            max_dist = ( nextSegment->m_Width + this->m_Width ) / 2;


            if( IsNear( position, nextSegment->m_Start, max_dist ) )
    while( nextSegment || previousSegment )
    {
    {
                if( Reflayer & nextSegment->GetLayerMask() )
        // Terminate the search in the direction if the netcode mismatches
                    return nextSegment;
        if( aSameNetOnly )
        {
            if( nextSegment && (nextSegment->GetNetCode() != GetNetCode()) )
                nextSegment = NULL;
            if( previousSegment && (previousSegment->GetNetCode() != GetNetCode()) )
                previousSegment = NULL;
        }
        }


            if( IsNear( position, nextSegment->m_End, max_dist ) )
        if( nextSegment )
        {
            if ( (nextSegment != this) && 
                 !nextSegment->GetState( BUSY | IS_DELETED ) &&
                 (refLayers & nextSegment->GetLayerMask()) )
            {
            {
                if( Reflayer & nextSegment->GetLayerMask() )
                if( (position == nextSegment->m_Start) ||
                    (position == nextSegment->m_End) )
                    return nextSegment;
                    return nextSegment;
            }
            }
suite:

            // Keep looking forward
            if( nextSegment == aEndTrace )
            if( nextSegment == aEndTrace )
                nextSegment = NULL;
                nextSegment = NULL;
            else
            else
                nextSegment = nextSegment->Next();
                nextSegment = nextSegment->Next();
        }
        }


        // Same as above, looking back. During sequential search this branch is inactive
        if( previousSegment )
        if( previousSegment )
        {
        {
            if( previousSegment->GetState( BUSY | IS_DELETED ) )
            if ( (previousSegment != this) &&
                goto suite1;
                 !previousSegment->GetState( BUSY | IS_DELETED ) &&

                 (refLayers & previousSegment->GetLayerMask()) )
            if( previousSegment == this )
                goto suite1;

            max_dist = ( previousSegment->m_Width + m_Width ) / 2;

            if( IsNear( position, previousSegment->m_Start, max_dist ) )
            {
            {
                if( Reflayer & previousSegment->GetLayerMask() )
                if( (position == previousSegment->m_Start) ||
                    (position == previousSegment->m_End) )
                    return previousSegment;
                    return previousSegment;
            }
            }


            if( IsNear( position, previousSegment->m_End, max_dist ) )
            {
                if( Reflayer & previousSegment->GetLayerMask() )
                    return previousSegment;
            }
suite1:
            if( previousSegment == aStartTrace )
            if( previousSegment == aStartTrace )
                previousSegment = NULL;
                previousSegment = NULL;
            else if( previousSegment->Type() != PCB_T )
                previousSegment =  previousSegment->Back();
            else
            else
                previousSegment = NULL;
                previousSegment = previousSegment->Back();
        }
    }

    // General search
    for( nextSegment = aStartTrace; nextSegment != NULL; nextSegment =  nextSegment->Next() )
    {
        if( nextSegment->GetState( IS_DELETED | BUSY ) )
        {
            if( nextSegment == aEndTrace )
                break;

            continue;
        }

        if( nextSegment == this )
        {
            if( nextSegment == aEndTrace )
                break;

            continue;
        }

        max_dist = ( nextSegment->m_Width + m_Width ) / 2;

        if( IsNear( position, nextSegment->m_Start, max_dist ) )
        {
            if( Reflayer & nextSegment->GetLayerMask() )
                return nextSegment;
        }

        if( IsNear( position, nextSegment->m_End, max_dist ) )
        {
            if( Reflayer & nextSegment->GetLayerMask() )
                return nextSegment;
        }
        }

        if( nextSegment == aEndTrace )
            break;
    }
    }


    return NULL;
    return NULL;
+6 −1
Original line number Original line Diff line number Diff line
@@ -261,9 +261,14 @@ public:
     * @param aEndTrace A pointer to the TRACK object to stop the search.  A NULL value
     * @param aEndTrace A pointer to the TRACK object to stop the search.  A NULL value
     *                  searches to the end of the list.
     *                  searches to the end of the list.
     * @param aEndPoint The start or end point of the segment to test against.
     * @param aEndPoint The start or end point of the segment to test against.
     * @param aSameNetOnly if true stop searching when the netcode changes
     * @param aSequential If true, forces a forward sequential search,
     * which is restartable; the default search can be faster but the
     * position of the returned track in the list is unpredictable
     * @return A TRACK object pointer if found otherwise NULL.
     * @return A TRACK object pointer if found otherwise NULL.
     */
     */
    TRACK* GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint );
    TRACK* GetTrack( TRACK* aStartTrace, TRACK* aEndTrace, ENDPOINT_T aEndPoint,
            bool aSameNetOnly, bool aSequential );


    /**
    /**
     * Function GetEndSegments
     * Function GetEndSegments
+51 −119
Original line number Original line Diff line number Diff line
@@ -303,7 +303,7 @@ bool TRACKS_CLEANER::testTrackEndpointDangling( TRACK *aTrack, ENDPOINT_T aEndPo
{
{
    bool flag_erase = false;
    bool flag_erase = false;


    TRACK* other = aTrack->GetTrack( m_Brd->m_Track, NULL, aEndPoint );
    TRACK* other = aTrack->GetTrack( m_Brd->m_Track, NULL, aEndPoint, true, false );
    if( (other == NULL) &&
    if( (other == NULL) &&
            (zoneForTrackEndpoint( aTrack, aEndPoint ) == NULL) )
            (zoneForTrackEndpoint( aTrack, aEndPoint ) == NULL) )
        flag_erase = true; // Start endpoint is neither on pad, zone or other track
        flag_erase = true; // Start endpoint is neither on pad, zone or other track
@@ -324,7 +324,7 @@ bool TRACKS_CLEANER::testTrackEndpointDangling( TRACK *aTrack, ENDPOINT_T aEndPo
            // search for another segment following the via
            // search for another segment following the via
            aTrack->SetState( BUSY, true );
            aTrack->SetState( BUSY, true );


            other = via->GetTrack( m_Brd->m_Track, NULL, aEndPoint );
            other = via->GetTrack( m_Brd->m_Track, NULL, aEndPoint, true, false );


            // There is a via on the start but it goes nowhere
            // There is a via on the start but it goes nowhere
            if( (other == NULL) &&
            if( (other == NULL) &&
@@ -450,41 +450,37 @@ bool TRACKS_CLEANER::remove_duplicates_of_track( const TRACK *aTrack )
bool TRACKS_CLEANER::merge_collinear_of_track( TRACK *aSegment )
bool TRACKS_CLEANER::merge_collinear_of_track( TRACK *aSegment )
{
{
    bool merged_this = false;
    bool merged_this = false;
    bool flag = false; // If there are connections to this on the endpoint


    // search for a possible point connected to the START point of the current segment
    // *WHY* doesn't C++ have prec and succ (or ++ --) like PASCAL?
    TRACK *segStart = aSegment->Next();
    for( ENDPOINT_T endpoint = ENDPOINT_START; endpoint <= ENDPOINT_END;
    while( true )
            endpoint = ENDPOINT_T( endpoint + 1 ) )
    {
    {
        segStart = aSegment->GetTrack( segStart, NULL, ENDPOINT_START );
        // search for a possible segment connected to the current endpoint of the current one

        TRACK *other = aSegment->Next();
        if( segStart )
        if( other )
        {
        {
            // the two segments must have the same width
            other = aSegment->GetTrack( other, NULL, endpoint, true, false );
            if( aSegment->GetWidth() != segStart->GetWidth() )
                break;

            // it cannot be a via
            if( segStart->Type() != PCB_TRACE_T )
                break;

            // We must have only one segment connected
            segStart->SetState( BUSY, true );
            TRACK *other = aSegment->GetTrack( m_Brd->m_Track, NULL, ENDPOINT_START );
            segStart->SetState( BUSY, false );


            if( other == NULL )
            if( other )
                flag = true;           // OK
            {

                // the two segments must have the same width and the other
            break;
                // cannot be a via
        }
                if( (aSegment->GetWidth() == other->GetWidth()) && 
        break;
                        (other->Type() == PCB_TRACE_T) )
    }
                {
                    // There can be only one segment connected
                    other->SetState( BUSY, true );
                    TRACK *yet_another = aSegment->GetTrack( m_Brd->m_Track, NULL,
                            endpoint, true, false );
                    other->SetState( BUSY, false );


    if( flag )   // We have the starting point of the segment is connected to an other segment
                    if( !yet_another )
                    {
                    {
        TRACK *segDelete = mergeCollinearSegmentIfPossible( aSegment, segStart, ENDPOINT_START );
                        // Try to merge them
                        TRACK *segDelete = mergeCollinearSegmentIfPossible( aSegment,
                                other, endpoint );


                        // Merge succesful, the other one has to go away
                        if( segDelete )
                        if( segDelete )
                        {
                        {
                            m_Brd->GetRatsnest()->Remove( segDelete );
                            m_Brd->GetRatsnest()->Remove( segDelete );
@@ -493,52 +489,11 @@ bool TRACKS_CLEANER::merge_collinear_of_track( TRACK *aSegment )
                            merged_this = true;
                            merged_this = true;
                        }
                        }
                    }
                    }

    // Do the same with the other endpoint
    flag = false;

    // search for a possible point connected to the END point of the current segment:
    TRACK *segEnd = aSegment->Next();
    while( true )
    {
        segEnd = aSegment->GetTrack( segEnd, NULL, ENDPOINT_END );

        if( segEnd )
        {
            if( aSegment->GetWidth() != segEnd->GetWidth() )
                break;

            if( segEnd->Type() != PCB_TRACE_T )
                break;

            // We must have only one segment connected
            segEnd->SetState( BUSY, true );
            TRACK *other = aSegment->GetTrack( m_Brd->m_Track, NULL, ENDPOINT_END );
            segEnd->SetState( BUSY, false );

            if( other == NULL )
                flag = true;        // Ok

            break;
        }
        else
        {
            break;
                }
                }
            }
            }

    if( flag  )  // We have the ending point of the segment is connected to an other segment
    {
        TRACK *segDelete = mergeCollinearSegmentIfPossible( aSegment, segEnd, ENDPOINT_END );

        if( segDelete )
        {
            m_Brd->GetRatsnest()->Remove( segDelete );
            segDelete->ViewRelease();
            segDelete->DeleteStructure();
            merged_this = true;
        }
        }
    }
    }

    return merged_this;
    return merged_this;
}
}


@@ -550,12 +505,9 @@ bool TRACKS_CLEANER::clean_segments()
    // Easy things first
    // Easy things first
    modified |= delete_null_segments();
    modified |= delete_null_segments();


    // Delete redundant segments, i.e. segments having the same end points
    // Delete redundant segments, i.e. segments having the same end points and layers
    // and layers
    for( TRACK *segment = m_Brd->m_Track; segment; segment = segment->Next() )
    for( TRACK *segment = m_Brd->m_Track; segment; segment = segment->Next() )
    {
        modified |= remove_duplicates_of_track( segment );
        modified |= remove_duplicates_of_track( segment );
    }


    // merge collinear segments:
    // merge collinear segments:
    TRACK *nextsegment;
    TRACK *nextsegment;
@@ -568,7 +520,7 @@ bool TRACKS_CLEANER::clean_segments()
            bool merged_this = merge_collinear_of_track( segment );
            bool merged_this = merge_collinear_of_track( segment );
            modified |= merged_this;
            modified |= merged_this;


            if( merged_this ) // The current segment was modified, retry to merge it
            if( merged_this ) // The current segment was modified, retry to merge it again
                nextsegment = segment->Next();
                nextsegment = segment->Next();
        }
        }
    }
    }
@@ -579,44 +531,24 @@ bool TRACKS_CLEANER::clean_segments()
/* Utility: check for parallelism between two segments */
/* Utility: check for parallelism between two segments */
static bool parallelism_test( int dx1, int dy1, int dx2, int dy2 )
static bool parallelism_test( int dx1, int dy1, int dx2, int dy2 )
{
{
    // The following condition tree is ugly and repetitive, but I have
    /* The following condition list is ugly and repetitive, but I have
    // not a better way to express clearly the trivial cases. Hope the
     * not a better way to express clearly the trivial cases. Hope the
    // compiler optimize it better than always doing the product
     * compiler optimize it better than always doing the product
    // below...
     * below... */


    // test for vertical alignment (easy to handle)
    // test for vertical alignment (easy to handle)
    if( dx1 == 0 )
    if( dx1 == 0 )
    {
        return dx2 == 0;
        if( dx2 != 0 )
            return false;
        else
            return true;
    }


    if( dx2 == 0 )
    if( dx2 == 0 )
    {
        return dx1 == 0;
        if( dx1 != 0 )
            return false;
        else
            return true;
    }


    // test for horizontal alignment (easy to handle)
    // test for horizontal alignment (easy to handle)
    if( dy1 == 0 )
    if( dy1 == 0 )
    {
        return dy2 == 0;
        if( dy2 != 0 )
            return false;
        else
            return true;
    }


    if( dy2 == 0 )
    if( dy2 == 0 )
    {
        return dy1 == 0;
        if( dy1 != 0 )
            return false;
        else
            return true;
    }


    /* test for alignment in other cases: Do the usual cross product test 
    /* test for alignment in other cases: Do the usual cross product test 
     * (the same as testing the slope, but without a division) */
     * (the same as testing the slope, but without a division) */
@@ -746,7 +678,7 @@ bool PCB_EDIT_FRAME::RemoveMisConnectedTracks()
        }
        }
        else
        else
        {
        {
            other = segment->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START );
            other = segment->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, false, false );


            if( other )
            if( other )
                net_code_s = other->GetNetCode();
                net_code_s = other->GetNetCode();
@@ -764,7 +696,7 @@ bool PCB_EDIT_FRAME::RemoveMisConnectedTracks()
        }
        }
        else
        else
        {
        {
            other = segment->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END );
            other = segment->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, false, false );


            if( other )
            if( other )
                net_code_e = other->GetNetCode();
                net_code_e = other->GetNetCode();
+4 −4
Original line number Original line Diff line number Diff line
@@ -709,7 +709,7 @@ void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC* DC
    s_StartSegmentPresent = s_EndSegmentPresent = true;
    s_StartSegmentPresent = s_EndSegmentPresent = true;


    if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) )
    if( ( track->start == NULL ) || ( track->start->Type() == PCB_TRACE_T ) )
        TrackToStartPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START );
        TrackToStartPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false );


    //  Test if more than one segment is connected to this point
    //  Test if more than one segment is connected to this point
    if( TrackToStartPoint )
    if( TrackToStartPoint )
@@ -717,14 +717,14 @@ void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC* DC
        TrackToStartPoint->SetState( BUSY, true );
        TrackToStartPoint->SetState( BUSY, true );


        if( ( TrackToStartPoint->Type() == PCB_VIA_T )
        if( ( TrackToStartPoint->Type() == PCB_VIA_T )
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START ) )
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_START, true, false ) )
            error = true;
            error = true;


        TrackToStartPoint->SetState( BUSY, false );
        TrackToStartPoint->SetState( BUSY, false );
    }
    }


    if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) )
    if( ( track->end == NULL ) || ( track->end->Type() == PCB_TRACE_T ) )
        TrackToEndPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END );
        TrackToEndPoint = track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false );


    //  Test if more than one segment is connected to this point
    //  Test if more than one segment is connected to this point
    if( TrackToEndPoint )
    if( TrackToEndPoint )
@@ -732,7 +732,7 @@ void PCB_EDIT_FRAME::Start_DragTrackSegmentAndKeepSlope( TRACK* track, wxDC* DC
        TrackToEndPoint->SetState( BUSY, true );
        TrackToEndPoint->SetState( BUSY, true );


        if( (TrackToEndPoint->Type() == PCB_VIA_T)
        if( (TrackToEndPoint->Type() == PCB_VIA_T)
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END ) )
           || track->GetTrack( GetBoard()->m_Track, NULL, ENDPOINT_END, true, false ) )
            error = true;
            error = true;


        TrackToEndPoint->SetState( BUSY, false );
        TrackToEndPoint->SetState( BUSY, false );