KiCad PCB EDA Suite
pns_joint.h
Go to the documentation of this file.
1 /*
2  * KiRouter - a push-and-(sometimes-)shove PCB router
3  *
4  * Copyright (C) 2013-2014 CERN
5  * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * @author Tomasz Wlostowski <[email protected]>
8  *
9  * This program is free software: you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation, either version 3 of the License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #ifndef __PNS_JOINT_H
24 #define __PNS_JOINT_H
25 
26 #include <vector>
27 
28 #include <math/vector2d.h>
29 
30 #include "pns_item.h"
31 #include "pns_segment.h"
32 #include "pns_itemset.h"
33 
34 namespace PNS {
35 
42 class JOINT : public ITEM
43 {
44 public:
46 
49  struct HASH_TAG
50  {
52  int net;
53  };
54 
56  {
57  std::size_t operator()( const JOINT::HASH_TAG& aP ) const
58  {
59  using std::size_t;
60  using std::hash;
61  using std::string;
62 
63  return ( (hash<int>()( aP.pos.x )
64  ^ (hash<int>()( aP.pos.y ) << 1) ) >> 1 )
65  ^ (hash<int>()( aP.net ) << 1);
66  }
67  };
68 
69  JOINT() :
70  ITEM( JOINT_T ), m_tag(), m_locked( false ) {}
71 
72  JOINT( const VECTOR2I& aPos, const LAYER_RANGE& aLayers, int aNet = -1 ) :
73  ITEM( JOINT_T )
74  {
75  m_tag.pos = aPos;
76  m_tag.net = aNet;
77  m_layers = aLayers;
78  m_locked = false;
79  }
80 
81  JOINT( const JOINT& aB ) :
82  ITEM( JOINT_T )
83  {
84  m_layers = aB.m_layers;
85  m_tag.pos = aB.m_tag.pos;
86  m_tag.net = aB.m_tag.net;
88  m_layers = aB.m_layers;
89  m_locked = aB.m_locked;
90  }
91 
92  ITEM* Clone( ) const override
93  {
94  assert( false );
95  return nullptr;
96  }
97 
103  bool IsLineCorner( bool aAllowLockedSegs = false ) const
104  {
105  if( m_linkedItems.Size() != 2 || m_linkedItems.Count( SEGMENT_T | ARC_T ) != 2 )
106  {
107  if( !aAllowLockedSegs )
108  {
109  return false;
110  }
111  // There will be multiple VVIAs on joints between two locked segments, because we
112  // naively add a VVIA to each end of a locked segment.
113  else if( ( m_linkedItems.Size() - m_linkedItems.Count( SEGMENT_T | ARC_T ) )
114  == m_linkedItems.Count( VIA_T ) )
115  {
116  const VIA* via = nullptr;
117  bool hasNonVirtualVia = false;
118 
119  for( const ITEM* item : m_linkedItems.CItems() )
120  {
121  if( item->Kind() == VIA_T )
122  {
123  via = static_cast<const VIA*>( item );
124 
125  hasNonVirtualVia = !via->IsVirtual();
126 
127  if( hasNonVirtualVia )
128  break;
129  }
130  }
131 
132  assert( via );
133 
134  if( !via || hasNonVirtualVia )
135  return false;
136  }
137  else
138  {
139  return false;
140  }
141  }
142 
143  auto seg1 = static_cast<LINKED_ITEM*>( m_linkedItems[0] );
144  auto seg2 = static_cast<LINKED_ITEM*>( m_linkedItems[1] );
145 
146  // joints between segments of different widths are not considered trivial.
147  return seg1->Width() == seg2->Width();
148  }
149 
150  bool IsNonFanoutVia() const
151  {
152  int vias = m_linkedItems.Count( VIA_T );
153  int segs = m_linkedItems.Count( SEGMENT_T );
154  segs += m_linkedItems.Count( ARC_T );
155 
156  return ( m_linkedItems.Size() == 3 && vias == 1 && segs == 2 );
157  }
158 
159  bool IsStitchingVia() const
160  {
161  return ( m_linkedItems.Size() == 1 && m_linkedItems.Count( VIA_T ) == 1 );
162  }
163 
164  bool IsTraceWidthChange() const
165  {
166  if( m_linkedItems.Size() != 2 )
167  return false;
168 
169  if( m_linkedItems.Count( SEGMENT_T ) != 2)
170  return false;
171 
172  SEGMENT* seg1 = static_cast<SEGMENT*>( m_linkedItems[0] );
173  SEGMENT* seg2 = static_cast<SEGMENT*>( m_linkedItems[1] );
174 
175  return seg1->Width() != seg2->Width();
176  }
177 
179  void Link( ITEM* aItem )
180  {
181  if( m_linkedItems.Contains( aItem ) )
182  return;
183 
184  m_linkedItems.Add( aItem );
185  }
186 
189  bool Unlink( ITEM* aItem )
190  {
191  m_linkedItems.Erase( aItem );
192  return m_linkedItems.Size() == 0;
193  }
194 
197  LINKED_ITEM* NextSegment( ITEM* aCurrent, bool aAllowLockedSegs = false ) const
198  {
199  if( !IsLineCorner( aAllowLockedSegs ) )
200  return nullptr;
201 
202  return static_cast<LINKED_ITEM*>( m_linkedItems[m_linkedItems[0] == aCurrent ? 1 : 0] );
203  }
204 
205  VIA* Via()
206  {
207  for( ITEM* item : m_linkedItems.Items() )
208  {
209  if( item->OfKind( VIA_T ) )
210  return static_cast<VIA*>( item );
211  }
212 
213  return nullptr;
214  }
215 
216 
218  const HASH_TAG& Tag() const
219  {
220  return m_tag;
221  }
222 
223  const VECTOR2I& Pos() const
224  {
225  return m_tag.pos;
226  }
227 
228  int Net() const
229  {
230  return m_tag.net;
231  }
232 
233  const LINKED_ITEMS& LinkList() const
234  {
235  return m_linkedItems.CItems();
236  }
237 
238  const ITEM_SET& CLinks() const
239  {
240  return m_linkedItems;
241  }
242 
244  {
245  return m_linkedItems;
246  }
247 
248  int LinkCount( int aMask = -1 ) const
249  {
250  return m_linkedItems.Count( aMask );
251  }
252 
253  void Dump() const;
254 
255  bool operator==( const JOINT& rhs ) const
256  {
257  return m_tag.pos == rhs.m_tag.pos && m_tag.net == rhs.m_tag.net;
258  }
259 
260  void Merge( const JOINT& aJoint )
261  {
262  if( !Overlaps( aJoint ) )
263  return;
264 
265  m_layers.Merge( aJoint.m_layers );
266 
267  if( aJoint.IsLocked() )
268  m_locked = true;
269 
270  for( ITEM* item : aJoint.LinkList() )
271  {
272  m_linkedItems.Add( item );
273  }
274  }
275 
276  bool Overlaps( const JOINT& rhs ) const
277  {
278  return m_tag.pos == rhs.m_tag.pos &&
279  m_tag.net == rhs.m_tag.net && m_layers.Overlaps( rhs.m_layers );
280  }
281 
282  void Lock( bool aLock = true )
283  {
284  m_locked = aLock;
285  }
286 
287  bool IsLocked() const
288  {
289  return m_locked;
290  }
291 
292 private:
295 
298 
300  bool m_locked;
301 };
302 
303 inline bool operator==( JOINT::HASH_TAG const& aP1, JOINT::HASH_TAG const& aP2 )
304 {
305  return aP1.pos == aP2.pos && aP1.net == aP2.net;
306 }
307 
308 }
309 
310 #endif // __PNS_JOINT_H
Base class for PNS router board items.
Definition: pns_item.h:55
int Count(int aKindMask=-1) const
Definition: pns_itemset.h:114
bool IsTraceWidthChange() const
Link the joint to a given board item (when it's added to the NODE).
Definition: pns_joint.h:164
bool Contains(ITEM *aItem) const
Definition: pns_itemset.h:193
bool Unlink(ITEM *aItem)
For trivial joints, return the segment adjacent to (aCurrent).
Definition: pns_joint.h:189
int Width() const override
Definition: pns_segment.h:79
ENTRIES & Items()
Definition: pns_itemset.h:135
bool IsLocked() const
Definition: pns_joint.h:287
bool Overlaps(const LAYER_RANGE &aOther) const
Definition: pns_layerset.h:67
LAYER_RANGE m_layers
Definition: pns_item.h:251
ITEM_SET m_linkedItems
locked (non-movable) flag
Definition: pns_joint.h:297
bool IsLineCorner(bool aAllowLockedSegs=false) const
Checks if a joint connects two segments of the same net, layer, and width.
Definition: pns_joint.h:103
void Lock(bool aLock=true)
Definition: pns_joint.h:282
std::vector< ENTRY > ENTRIES
Definition: pns_itemset.h:93
int Size() const
Definition: pns_itemset.h:160
void Erase(ITEM *aItem)
Definition: pns_itemset.h:199
int Net() const
Definition: pns_joint.h:228
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
ITEM_SET & Links()
Definition: pns_joint.h:243
JOINT(const VECTOR2I &aPos, const LAYER_RANGE &aLayers, int aNet=-1)
Definition: pns_joint.h:72
A 2D point on a given set of layers and belonging to a certain net, that links together a number of b...
Definition: pns_joint.h:42
bool m_locked
Definition: pns_joint.h:300
void Merge(const LAYER_RANGE &aOther)
Shortcut for comparisons/overlap tests.
Definition: pns_layerset.h:92
const HASH_TAG & Tag() const
trivial accessors
Definition: pns_joint.h:218
ITEM_SET::ENTRIES LINKED_ITEMS
Joints are hashed by their position, layers and net.
Definition: pns_joint.h:45
const LINKED_ITEMS & LinkList() const
Definition: pns_joint.h:233
const ITEM_SET & CLinks() const
Definition: pns_joint.h:238
bool operator==(JOINT::HASH_TAG const &aP1, JOINT::HASH_TAG const &aP2)
Definition: pns_joint.h:303
bool operator==(const JOINT &rhs) const
Definition: pns_joint.h:255
std::size_t operator()(const JOINT::HASH_TAG &aP) const
Definition: pns_joint.h:57
JOINT(const JOINT &aB)
Definition: pns_joint.h:81
VIA * Via()
Definition: pns_joint.h:205
void Dump() const
Definition: pns_node.cpp:1242
HASH_TAG m_tag
< hash tag for unordered_multimap
Definition: pns_joint.h:294
bool Overlaps(const JOINT &rhs) const
Definition: pns_joint.h:276
const ENTRIES & CItems() const
Definition: pns_itemset.h:136
void Merge(const JOINT &aJoint)
Definition: pns_joint.h:260
bool IsStitchingVia() const
Definition: pns_joint.h:159
ITEM * Clone() const override
Return a deep copy of the item.
Definition: pns_joint.h:92
int LinkCount(int aMask=-1) const
Definition: pns_joint.h:248
const VECTOR2I & Pos() const
Definition: pns_joint.h:223
LINKED_ITEM * NextSegment(ITEM *aCurrent, bool aAllowLockedSegs=false) const
Definition: pns_joint.h:197
void Link(ITEM *aItem)
Unlink a given board item from the joint (upon its removal from a NODE)
Definition: pns_joint.h:179
Push and Shove diff pair dimensions (gap) settings dialog.
bool IsNonFanoutVia() const
Definition: pns_joint.h:150
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:31