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