bool PNS_LINE_PLACER::buildInitialLine( const VECTOR2I& aP, PNS_LINE& aHead )
{
    SHAPE_LINE_CHAIN l;

    if( m_p_start == aP )
    {
        l.Clear();
    }
    else
    {
        if( Settings().GetFreeAngleMode() && Settings().Mode() == RM_MarkObstacles )
        {
            l = SHAPE_LINE_CHAIN( m_p_start, aP );
        }
        else
        {
            l = m_direction.BuildInitialTrace( m_p_start, aP );
        }

        if( l.SegmentCount() > 1 && m_orthoMode )
        {
            VECTOR2I newLast = l.CSegment( 0 ).LineProject( l.CPoint( -1 ) );

            l.Remove( -1, -1 );
            l.Point( 1 ) = newLast;
        }
    }

    aHead.SetShape( l );

    if( !m_placingVia )
        return true;

    PNS_VIA v( makeVia( aP ) );
    v.SetNet( aHead.Net() );

    if( m_currentMode == RM_MarkObstacles )
    {
        aHead.AppendVia( v );
        return true;
    }

    VECTOR2I force;
    VECTOR2I lead = aP - m_p_start;

    bool solidsOnly = ( m_currentMode != RM_Walkaround );

    if( v.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) )
    {
        SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP + force );
        aHead = PNS_LINE( aHead, line );

        v.SetPos( v.Pos() + force );
        return true;
    }

    return false; // via placement unsuccessful
}
Beispiel #2
0
static void drawGw( VECTOR2I p, int color )
{
    SHAPE_LINE_CHAIN l;

    l.Append( p - VECTOR2I( -50000, -50000 ) );
    l.Append( p + VECTOR2I( -50000, -50000 ) );

    l.Clear();
    l.Append( p - VECTOR2I( 50000, -50000 ) );
    l.Append( p + VECTOR2I( 50000, -50000 ) );
}
Beispiel #3
0
    void AddPoint( VECTOR2I aP, int aColor )
    {
        SHAPE_LINE_CHAIN l;

        l.Append( aP - VECTOR2I( -50000, -50000 ) );
        l.Append( aP + VECTOR2I( -50000, -50000 ) );

        AddLine ( l, aColor, 10000 );

        l.Clear();
        l.Append( aP - VECTOR2I( 50000, -50000 ) );
        l.Append( aP + VECTOR2I( 50000, -50000 ) );

        AddLine( l, aColor, 10000 );
    }
Beispiel #4
0
void DrawDebugPoint( VECTOR2I aP, int aColor )
{
    SHAPE_LINE_CHAIN l;

    l.Append( aP - VECTOR2I( -50000, -50000 ) );
    l.Append( aP + VECTOR2I( -50000, -50000 ) );

    ROUTER::GetInstance()->DisplayDebugLine ( l, aColor, 10000 );

    l.Clear();
    l.Append( aP - VECTOR2I( 50000, -50000 ) );
    l.Append( aP + VECTOR2I( 50000, -50000 ) );

    ROUTER::GetInstance()->DisplayDebugLine( l, aColor, 10000 );
}
bool PNS_TOPOLOGY::LeadingRatLine( const PNS_LINE* aTrack, SHAPE_LINE_CHAIN& aRatLine )
{
    PNS_LINE track( *aTrack );
    VECTOR2I end;

    if( !track.PointCount() )
        return false;

    std::unique_ptr<PNS_NODE> tmpNode( m_world->Branch() );
    tmpNode->Add( &track );

    PNS_JOINT* jt = tmpNode->FindJoint( track.CPoint( -1 ), &track );

    if( !jt )
       return false;

    if( ( !track.EndsWithVia() && jt->LinkCount() >= 2 ) || ( track.EndsWithVia() && jt->LinkCount() >= 3 ) ) // we got something connected
    {
        end = jt->Pos();
    }
    else
    {
        int anchor;

        PNS_TOPOLOGY topo( tmpNode.get() );
        PNS_ITEM* it = topo.NearestUnconnectedItem( jt, &anchor );

        if( !it )
            return false;

        end = it->Anchor( anchor );
    }

    aRatLine.Clear();
    aRatLine.Append( track.CPoint( -1 ) );
    aRatLine.Append( end );
    return true;
}
Beispiel #6
0
void ZONE_FILLER::buildUnconnectedThermalStubsPolygonList( SHAPE_POLY_SET& aCornerBuffer,
                                              const ZONE_CONTAINER*       aZone,
                                              const SHAPE_POLY_SET&       aRawFilledArea,
                                              double                aArcCorrection,
                                              double                aRoundPadThermalRotation ) const
{
    SHAPE_LINE_CHAIN spokes;
    BOX2I itemBB;
    VECTOR2I ptTest[4];
    auto zoneBB = aRawFilledArea.BBox();


    int      zone_clearance = aZone->GetZoneClearance();

    int      biggest_clearance = m_board->GetDesignSettings().GetBiggestClearanceValue();
    biggest_clearance = std::max( biggest_clearance, zone_clearance );
    zoneBB.Inflate( biggest_clearance );

    // half size of the pen used to draw/plot zones outlines
    int pen_radius = aZone->GetMinThickness() / 2;

    for( auto module : m_board->Modules() )
    {
        for( auto pad : module->Pads() )
        {
            // Rejects non-standard pads with tht-only thermal reliefs
            if( aZone->GetPadConnection( pad ) == PAD_ZONE_CONN_THT_THERMAL
             && pad->GetAttribute() != PAD_ATTRIB_STANDARD )
                continue;

            if( aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THERMAL
             && aZone->GetPadConnection( pad ) != PAD_ZONE_CONN_THT_THERMAL )
                continue;

            if( !pad->IsOnLayer( aZone->GetLayer() ) )
                continue;

            if( pad->GetNetCode() != aZone->GetNetCode() )
                continue;

            // Calculate thermal bridge half width
            int thermalBridgeWidth = aZone->GetThermalReliefCopperBridge( pad )
                                     - aZone->GetMinThickness();
            if( thermalBridgeWidth <= 0 )
                continue;

            // we need the thermal bridge half width
            // with a small extra size to be sure we create a stub
            // slightly larger than the actual stub
            thermalBridgeWidth = ( thermalBridgeWidth + 4 ) / 2;

            int thermalReliefGap = aZone->GetThermalReliefGap( pad );

            itemBB = pad->GetBoundingBox();
            itemBB.Inflate( thermalReliefGap );
            if( !( itemBB.Intersects( zoneBB ) ) )
                continue;

            // Thermal bridges are like a segment from a starting point inside the pad
            // to an ending point outside the pad

            // calculate the ending point of the thermal pad, outside the pad
            VECTOR2I endpoint;
            endpoint.x = ( pad->GetSize().x / 2 ) + thermalReliefGap;
            endpoint.y = ( pad->GetSize().y / 2 ) + thermalReliefGap;

            // Calculate the starting point of the thermal stub
            // inside the pad
            VECTOR2I startpoint;
            int copperThickness = aZone->GetThermalReliefCopperBridge( pad )
                                  - aZone->GetMinThickness();

            if( copperThickness < 0 )
                copperThickness = 0;

            // Leave a small extra size to the copper area inside to pad
            copperThickness += KiROUND( IU_PER_MM * 0.04 );

            startpoint.x = std::min( pad->GetSize().x, copperThickness );
            startpoint.y = std::min( pad->GetSize().y, copperThickness );

            startpoint.x /= 2;
            startpoint.y /= 2;

            // This is a CIRCLE pad tweak
            // for circle pads, the thermal stubs orientation is 45 deg
            double fAngle = pad->GetOrientation();
            if( pad->GetShape() == PAD_SHAPE_CIRCLE )
            {
                endpoint.x     = KiROUND( endpoint.x * aArcCorrection );
                endpoint.y     = endpoint.x;
                fAngle = aRoundPadThermalRotation;
            }

            // contour line width has to be taken into calculation to avoid "thermal stub bleed"
            endpoint.x += pen_radius;
            endpoint.y += pen_radius;
            // compute north, south, west and east points for zone connection.
            ptTest[0] = VECTOR2I( 0, endpoint.y );       // lower point
            ptTest[1] = VECTOR2I( 0, -endpoint.y );      // upper point
            ptTest[2] = VECTOR2I( endpoint.x, 0 );       // right point
            ptTest[3] = VECTOR2I( -endpoint.x, 0 );      // left point

            // Test all sides
            for( int i = 0; i < 4; i++ )
            {
                // rotate point
                RotatePoint( ptTest[i], fAngle );

                // translate point
                ptTest[i] += pad->ShapePos();

                if( aRawFilledArea.Contains( ptTest[i] ) )
                    continue;

                spokes.Clear();

                // polygons are rectangles with width of copper bridge value
                switch( i )
                {
                case 0:       // lower stub
                    spokes.Append( -thermalBridgeWidth, endpoint.y );
                    spokes.Append( +thermalBridgeWidth, endpoint.y );
                    spokes.Append( +thermalBridgeWidth, startpoint.y );
                    spokes.Append( -thermalBridgeWidth, startpoint.y );
                    break;

                case 1:       // upper stub
                    spokes.Append( -thermalBridgeWidth, -endpoint.y );
                    spokes.Append( +thermalBridgeWidth, -endpoint.y );
                    spokes.Append( +thermalBridgeWidth, -startpoint.y );
                    spokes.Append( -thermalBridgeWidth, -startpoint.y );
                    break;

                case 2:       // right stub
                    spokes.Append( endpoint.x, -thermalBridgeWidth );
                    spokes.Append( endpoint.x, thermalBridgeWidth );
                    spokes.Append( +startpoint.x, thermalBridgeWidth );
                    spokes.Append( +startpoint.x, -thermalBridgeWidth );
                    break;

                case 3:       // left stub
                    spokes.Append( -endpoint.x, -thermalBridgeWidth );
                    spokes.Append( -endpoint.x, thermalBridgeWidth );
                    spokes.Append( -startpoint.x, thermalBridgeWidth );
                    spokes.Append( -startpoint.x, -thermalBridgeWidth );
                    break;
                }

                aCornerBuffer.NewOutline();

                // add computed polygon to list
                for( int ic = 0; ic < spokes.PointCount(); ic++ )
                {
                    auto cpos = spokes.CPoint( ic );
                    RotatePoint( cpos, fAngle );                               // Rotate according to module orientation
                    cpos += pad->ShapePos();                              // Shift origin to position
                    aCornerBuffer.Append( cpos );
                }
            }
        }
    }
}
bool PNS_LINE::Walkaround( SHAPE_LINE_CHAIN aObstacle, SHAPE_LINE_CHAIN& aPre,
                           SHAPE_LINE_CHAIN& aWalk, SHAPE_LINE_CHAIN& aPost, bool aCw ) const
{
    const SHAPE_LINE_CHAIN& line ( CLine() );
    VECTOR2I ip_start;
    VECTOR2I ip_end;

    if( line.SegmentCount() < 1 )
        return false;

    if( aObstacle.PointInside( line.CPoint( 0 ) ) || aObstacle.PointInside( line.CPoint( -1 ) ) )
        return false;

    SHAPE_LINE_CHAIN::INTERSECTIONS ips, ips2;

    line.Intersect( aObstacle, ips );

    int nearest_dist = INT_MAX;
    int farthest_dist = 0;

    SHAPE_LINE_CHAIN::INTERSECTION nearest, farthest;

    for( int i = 0; i < (int) ips.size(); i++ )
    {
        const VECTOR2I p = ips[i].p;
        int dist = line.PathLength( p );

        if( dist < 0 )
            return false;

        if( dist <= nearest_dist )
        {
            nearest_dist = dist;
            nearest = ips[i];
        }

        if( dist >= farthest_dist )
        {
            farthest_dist = dist;
            farthest = ips[i];
        }
    }

    if( ips.size() <= 1 || nearest.p == farthest.p )
    {
        aPre = line;
        return true;
    }

    aPre = line.Slice( 0, nearest.our.Index() );
    aPre.Append( nearest.p );
    aPre.Simplify();

    aWalk.Clear();
    aWalk.SetClosed( false );
    aWalk.Append( nearest.p );

    int i = nearest.their.Index();

    assert( nearest.their.Index() >= 0 );
    assert( farthest.their.Index() >= 0 );

    assert( nearest_dist <= farthest_dist );

    aObstacle.Split( nearest.p );
    aObstacle.Split( farthest.p );

    int i_first = aObstacle.Find( nearest.p );
    int i_last = aObstacle.Find( farthest.p );

    i = i_first;

    while( i != i_last )
    {
        aWalk.Append( aObstacle.CPoint( i ) );
        i += ( aCw ? 1 : -1 );

        if( i < 0 )
            i = aObstacle.PointCount() - 1;
        else if( i == aObstacle.PointCount() )
            i = 0;
    }

    aWalk.Append( farthest.p );
    aWalk.Simplify();

    aPost.Clear();
    aPost.Append( farthest.p );
    aPost.Append( line.Slice( farthest.our.Index() + 1, -1 ) );
    aPost.Simplify();

    return true;
}