1 /*
2  * KiRouter - a push-and-(sometimes-)shove PCB router
3  *
4  * Copyright (C) 2013-2014 CERN
5  * Copyright (C) 2016-2020 KiCad Developers, see AUTHORS.txt for contributors.
6  * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
7  *
8  * This program is free software: you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the
10  * Free Software Foundation, either version 3 of the License, or (at your
11  * option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <zone.h>
23 #include "pns_node.h"
24 #include "pns_item.h"
25 #include "pns_line.h"
26 #include "pns_router.h"
27 
28 typedef VECTOR2I::extended_type ecoord;
29 
30 namespace PNS {
31 
collideSimple(const ITEM * aOther,const NODE * aNode,bool aDifferentNetsOnly) const32 bool ITEM::collideSimple( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly ) const
33 {
34     const ROUTER_IFACE* iface = ROUTER::GetInstance()->GetInterface();
35     const SHAPE*        shapeA = Shape();
36     const SHAPE*        holeA = Hole();
37     int                 lineWidthA = 0;
38     const SHAPE*        shapeB = aOther->Shape();
39     const SHAPE*        holeB = aOther->Hole();
40     int                 lineWidthB = 0;
41 
42     // Sadly collision routines ignore SHAPE_POLY_LINE widths so we have to pass them in as part
43     // of the clearance value.
44     if( m_kind == LINE_T )
45         lineWidthA = static_cast<const LINE*>( this )->Width() / 2;
46 
47     if( aOther->m_kind == LINE_T )
48         lineWidthB = static_cast<const LINE*>( aOther )->Width() / 2;
49 
50     // same nets? no collision!
51     if( aDifferentNetsOnly && m_net == aOther->m_net && m_net >= 0 && aOther->m_net >= 0 )
52         return false;
53 
54     // check if we are not on completely different layers first
55     if( !m_layers.Overlaps( aOther->m_layers ) )
56         return false;
57 
58     auto checkKeepout =
59             []( const ZONE* aKeepout, const BOARD_ITEM* aOther )
60             {
61                 constexpr KICAD_T TRACK_TYPES[] = { PCB_ARC_T, PCB_TRACE_T, EOT };
62 
63                 if( aKeepout->GetDoNotAllowTracks() && aOther->IsType( TRACK_TYPES ) )
64                     return true;
65 
66                 if( aKeepout->GetDoNotAllowVias() && aOther->Type() == PCB_VIA_T )
67                     return true;
68 
69                 if( aKeepout->GetDoNotAllowPads() && aOther->Type() == PCB_PAD_T )
70                     return true;
71 
72                 // Incomplete test, but better than nothing:
73                 if( aKeepout->GetDoNotAllowFootprints() && aOther->Type() == PCB_PAD_T )
74                 {
75                     return !aKeepout->GetParentFootprint()
76                             || aKeepout->GetParentFootprint() != aOther->GetParentFootprint();
77                 }
78 
79                 return false;
80             };
81 
82     const ZONE* zoneA = dynamic_cast<ZONE*>( Parent() );
83     const ZONE* zoneB = dynamic_cast<ZONE*>( aOther->Parent() );
84 
85     if( zoneA && aOther->Parent() && !checkKeepout( zoneA, aOther->Parent() ) )
86         return false;
87 
88     if( zoneB && Parent() && !checkKeepout( zoneB, Parent() ) )
89         return false;
90 
91     if( holeA || holeB )
92     {
93         int holeClearance = aNode->GetHoleClearance( this, aOther );
94 
95         if( holeA && holeA->Collide( shapeB, holeClearance + lineWidthB ) )
96         {
97             Mark( Marker() | MK_HOLE );
98             return true;
99         }
100 
101         if( holeB && holeB->Collide( shapeA, holeClearance + lineWidthA ) )
102         {
103             aOther->Mark( aOther->Marker() | MK_HOLE );
104             return true;
105         }
106 
107         if( holeA && holeB )
108         {
109             int holeToHoleClearance = aNode->GetHoleToHoleClearance( this, aOther );
110 
111             if( holeA->Collide( holeB, holeToHoleClearance ) )
112             {
113                 Mark( Marker() | MK_HOLE );
114                 aOther->Mark( aOther->Marker() | MK_HOLE );
115                 return true;
116             }
117         }
118     }
119 
120     if( !aOther->Layers().IsMultilayer() && !iface->IsFlashedOnLayer( this, aOther->Layer()) )
121         return false;
122 
123     if( !Layers().IsMultilayer() && !iface->IsFlashedOnLayer( aOther, Layer()) )
124         return false;
125 
126     int clearance = aNode->GetClearance( this, aOther );
127     return shapeA->Collide( shapeB, clearance + lineWidthA + lineWidthB );
128 }
129 
130 
Collide(const ITEM * aOther,const NODE * aNode,bool aDifferentNetsOnly) const131 bool ITEM::Collide( const ITEM* aOther, const NODE* aNode, bool aDifferentNetsOnly ) const
132 {
133     if( collideSimple( aOther, aNode, aDifferentNetsOnly ) )
134         return true;
135 
136     // Special cases for "head" lines with vias attached at the end.  Note that this does not
137     // support head-line-via to head-line-via collisions, but you can't route two independent
138     // tracks at once so it shouldn't come up.
139 
140     if( m_kind == LINE_T )
141     {
142         const LINE* line = static_cast<const LINE*>( this );
143 
144         if( line->EndsWithVia() && line->Via().collideSimple( aOther, aNode, aDifferentNetsOnly ) )
145             return true;
146     }
147 
148     if( aOther->m_kind == LINE_T )
149     {
150         const LINE* line = static_cast<const LINE*>( aOther );
151 
152         if( line->EndsWithVia() && line->Via().collideSimple( this, aNode, aDifferentNetsOnly ) )
153             return true;
154     }
155 
156     return false;
157 }
158 
159 
KindStr() const160 std::string ITEM::KindStr() const
161 {
162     switch( m_kind )
163     {
164     case ARC_T:       return "arc";
165     case LINE_T:      return "line";
166     case SEGMENT_T:   return "segment";
167     case VIA_T:       return "via";
168     case JOINT_T:     return "joint";
169     case SOLID_T:     return "solid";
170     case DIFF_PAIR_T: return "diff-pair";
171     default:          return "unknown";
172     }
173 }
174 
175 
~ITEM()176 ITEM::~ITEM()
177 {
178 }
179 
180 }
181