KiCad PCB EDA Suite
pns_topology.cpp
Go to the documentation of this file.
1/*
2 * KiRouter - a push-and-(sometimes-)shove PCB router
3 *
4 * Copyright (C) 2013-2015 CERN
5 * Copyright (C) 2016-2021 KiCad Developers, see AUTHORS.txt for contributors.
6 * Author: Tomasz Wlostowski <[email protected]>
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 "pns_line.h"
23#include "pns_segment.h"
24#include "pns_node.h"
25#include "pns_joint.h"
26#include "pns_solid.h"
27#include "pns_router.h"
28#include "pns_utils.h"
29
30#include "pns_diff_pair.h"
31#include "pns_topology.h"
32
33#include <board.h>
34#include <pad.h>
35
36namespace PNS {
37
39{
40 if( !aLine->IsLinked() || !aLine->SegmentCount() )
41 return false;
42
43 LINKED_ITEM* root = aLine->GetLink( 0 );
44 LINE l = m_world->AssembleLine( root );
45 SHAPE_LINE_CHAIN simplified( l.CLine() );
46
47 simplified.Simplify();
48
49 if( simplified.PointCount() != l.PointCount() )
50 {
51 m_world->Remove( l );
52 LINE lnew( l );
53 lnew.SetShape( simplified );
54 m_world->Add( lnew );
55 return true;
56 }
57
58 return false;
59}
60
61
63{
64 std::deque<JOINT*> searchQueue;
65 JOINT_SET processed;
66
67 searchQueue.push_back( aStart );
68 processed.insert( aStart );
69
70 while( !searchQueue.empty() )
71 {
72 JOINT* current = searchQueue.front();
73 searchQueue.pop_front();
74
75 for( ITEM* item : current->LinkList() )
76 {
77 if( item->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
78 {
79 JOINT* a = m_world->FindJoint( item->Anchor( 0 ), item );;
80 JOINT* b = m_world->FindJoint( item->Anchor( 1 ), item );;
81 JOINT* next = ( *a == *current ) ? b : a;
82
83 if( processed.find( next ) == processed.end() )
84 {
85 processed.insert( next );
86 searchQueue.push_back( next );
87 }
88 }
89 }
90 }
91
92 return processed;
93}
94
95
97 LAYER_RANGE& aLayers )
98{
99 LINE track( *aTrack );
100 VECTOR2I end;
101
102 if( !track.PointCount() )
103 return false;
104
105 std::unique_ptr<NODE> tmpNode( m_world->Branch() );
106 tmpNode->Add( track );
107
108 JOINT* jt = tmpNode->FindJoint( track.CPoint( -1 ), &track );
109
110 if( !jt || jt->Net() <= 0 )
111 return false;
112
113 if( ( !track.EndsWithVia() && jt->LinkCount() >= 2 )
114 || ( track.EndsWithVia() && jt->LinkCount() >= 3 ) ) // we got something connected
115 {
116 end = jt->Pos();
117 aLayers = jt->Layers();
118 }
119 else
120 {
121 int anchor;
122
123 TOPOLOGY topo( tmpNode.get() );
124 ITEM* it = topo.NearestUnconnectedItem( jt, &anchor );
125
126 if( !it )
127 return false;
128
129 end = it->Anchor( anchor );
130 aLayers = it->Layers();
131 }
132
133 aPoint = end;
134 return true;
135}
136
137
138bool TOPOLOGY::LeadingRatLine( const LINE* aTrack, SHAPE_LINE_CHAIN& aRatLine )
139{
140 VECTOR2I end;
141 // Ratline doesn't care about the layer
142 LAYER_RANGE layers;
143
144 if( !NearestUnconnectedAnchorPoint( aTrack, end, layers ) )
145 return false;
146
147 aRatLine.Clear();
148 aRatLine.Append( aTrack->CPoint( -1 ) );
149 aRatLine.Append( end );
150 return true;
151}
152
153
154ITEM* TOPOLOGY::NearestUnconnectedItem( JOINT* aStart, int* aAnchor, int aKindMask )
155{
156 std::set<ITEM*> disconnected;
157
158 m_world->AllItemsInNet( aStart->Net(), disconnected );
159
160 for( const JOINT* jt : ConnectedJoints( aStart ) )
161 {
162 for( ITEM* link : jt->LinkList() )
163 {
164 if( disconnected.find( link ) != disconnected.end() )
165 disconnected.erase( link );
166 }
167 }
168
169 int best_dist = INT_MAX;
170 ITEM* best = nullptr;
171
172 for( ITEM* item : disconnected )
173 {
174 if( item->OfKind( aKindMask ) )
175 {
176 for( int i = 0; i < item->AnchorCount(); i++ )
177 {
178 VECTOR2I p = item->Anchor( i );
179 int d = ( p - aStart->Pos() ).EuclideanNorm();
180
181 if( d < best_dist )
182 {
183 best_dist = d;
184 best = item;
185
186 if( aAnchor )
187 *aAnchor = i;
188 }
189 }
190 }
191 }
192
193 return best;
194}
195
196
197bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet,
198 std::set<ITEM*>& aVisited, JOINT** aTerminalJoint )
199{
200 assert( aLine->IsLinked() );
201
202 VECTOR2I anchor = aLeft ? aLine->CPoint( 0 ) : aLine->CPoint( -1 );
203 LINKED_ITEM* last = aLeft ? aLine->Links().front() : aLine->Links().back();
204 JOINT* jt = m_world->FindJoint( anchor, aLine );
205
206 assert( jt != nullptr );
207
208 aVisited.insert( last );
209
210 if( jt->IsNonFanoutVia() || jt->IsTraceWidthChange() )
211 {
212 ITEM* via = nullptr;
213 SEGMENT* next_seg = nullptr;
214
215 for( ITEM* link : jt->Links().Items() )
216 {
217 if( link->OfKind( ITEM::VIA_T ) )
218 via = link;
219 else if( aVisited.find( link ) == aVisited.end() )
220 next_seg = static_cast<SEGMENT*>( link );
221 }
222
223 if( !next_seg )
224 {
225 if( aTerminalJoint )
226 *aTerminalJoint = jt;
227
228 return false;
229 }
230
231 LINE l = m_world->AssembleLine( next_seg );
232
233 VECTOR2I nextAnchor = ( aLeft ? l.CLine().CPoint( -1 ) : l.CLine().CPoint( 0 ) );
234
235 if( nextAnchor != anchor )
236 {
237 l.Reverse();
238 }
239
240 if( aLeft )
241 {
242 if( via )
243 aSet.Prepend( via );
244
245 aSet.Prepend( l );
246 }
247 else
248 {
249 if( via )
250 aSet.Add( via );
251
252 aSet.Add( l );
253 }
254
255 return followTrivialPath( &l, aLeft, aSet, aVisited, aTerminalJoint );
256 }
257
258 if( aTerminalJoint )
259 *aTerminalJoint = jt;
260
261 return false;
262}
263
264
266 std::pair<JOINT*, JOINT*>* aTerminalJoints,
267 bool aFollowLockedSegments )
268{
270 std::set<ITEM*> visited;
271 LINKED_ITEM* seg = nullptr;
272
273 if( aStart->Kind() == ITEM::VIA_T )
274 {
275 VIA* via = static_cast<VIA*>( aStart );
276 JOINT* jt = m_world->FindJoint( via->Pos(), via );
277
278 if( !jt->IsNonFanoutVia() )
279 return ITEM_SET();
280
281 for( const ITEM_SET::ENTRY& entry : jt->Links().Items() )
282 {
283 if( entry.item->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
284 {
285 seg = static_cast<LINKED_ITEM*>( entry.item );
286 break;
287 }
288 }
289 }
290 else if( aStart->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
291 {
292 seg = static_cast<LINKED_ITEM*>( aStart );
293 }
294
295 if( !seg )
296 return ITEM_SET();
297
298 // Assemble a line following through locked segments
299 // TODO: consider if we want to allow tuning lines with different widths in the future
300 LINE l = m_world->AssembleLine( seg, nullptr, false, true );
301
302 path.Add( l );
303
304 JOINT* jointA = nullptr;
305 JOINT* jointB = nullptr;
306
307 followTrivialPath( &l, false, path, visited, &jointB );
308 followTrivialPath( &l, true, path, visited, &jointA );
309
310 if( aTerminalJoints )
311 {
312 wxASSERT( jointA && jointB );
313 *aTerminalJoints = std::make_pair( jointA, jointB );
314 }
315
316 return path;
317}
318
319
320const ITEM_SET TOPOLOGY::AssembleTuningPath( ITEM* aStart, SOLID** aStartPad, SOLID** aEndPad )
321{
322 std::pair<JOINT*, JOINT*> joints;
323 ITEM_SET initialPath = AssembleTrivialPath( aStart, &joints, true );
324
325 PAD* padA = nullptr;
326 PAD* padB = nullptr;
327
328 auto getPadFromJoint =
329 []( JOINT* aJoint, PAD** aTargetPad, SOLID** aTargetSolid )
330 {
331 for( ITEM* item : aJoint->LinkList() )
332 {
333 if( item->OfKind( ITEM::SOLID_T ) )
334 {
335 BOARD_ITEM* bi = static_cast<SOLID*>( item )->Parent();
336
337 if( bi->Type() == PCB_PAD_T )
338 {
339 *aTargetPad = static_cast<PAD*>( bi );
340
341 if( aTargetSolid )
342 *aTargetSolid = static_cast<SOLID*>( item );
343 }
344
345 break;
346 }
347 }
348 };
349
350 if( joints.first )
351 getPadFromJoint( joints.first, &padA, aStartPad );
352
353 if( joints.second )
354 getPadFromJoint( joints.second, &padB, aEndPad );
355
356 if( !padA && !padB )
357 return initialPath;
358
359 auto clipLineToPad =
360 []( SHAPE_LINE_CHAIN& aLine, PAD* aPad, bool aForward = true )
361 {
362 const std::shared_ptr<SHAPE_POLY_SET>& shape = aPad->GetEffectivePolygon();
363
364 int start = aForward ? 0 : aLine.PointCount() - 1;
365 int delta = aForward ? 1 : -1;
366
367 // Skip the "first" (or last) vertex, we already know it's contained in the pad
368 int clip = start;
369
370 for( int vertex = start + delta;
371 aForward ? vertex < aLine.PointCount() : vertex >= 0;
372 vertex += delta )
373 {
374 SEG seg( aLine.GetPoint( vertex ), aLine.GetPoint( vertex - delta ) );
375
376 bool containsA = shape->Contains( seg.A );
377 bool containsB = shape->Contains( seg.B );
378
379 if( containsA && containsB )
380 {
381 // Whole segment is inside: clip out this segment
382 clip = vertex;
383 }
384 else if( containsB )
385 {
386 // Only one point inside: Find the intersection
387 VECTOR2I loc;
388
389 if( shape->Collide( seg, 0, nullptr, &loc ) )
390 {
391 aLine.Replace( vertex - delta, vertex - delta, loc );
392 }
393 }
394 }
395
396 if( !aForward && clip < start )
397 aLine.Remove( clip + 1, start );
398 else if( clip > start )
399 aLine.Remove( start, clip - 1 );
400
401 // Now connect the dots
402 aLine.Insert( aForward ? 0 : aLine.PointCount(), aPad->GetPosition() );
403 };
404
405 auto processPad =
406 [&]( JOINT* aJoint, PAD* aPad )
407 {
408 const std::shared_ptr<SHAPE_POLY_SET>& shape = aPad->GetEffectivePolygon();
409
410 for( int idx = 0; idx < initialPath.Size(); idx++ )
411 {
412 if( initialPath[idx]->Kind() != ITEM::LINE_T )
413 continue;
414
415 LINE* line = static_cast<LINE*>( initialPath[idx] );
416
417 if( !aPad->FlashLayer( line->Layer() ) )
418 continue;
419
420 const std::vector<VECTOR2I>& points = line->CLine().CPoints();
421
422 if( points.front() != aJoint->Pos() && points.back() != aJoint->Pos() )
423 continue;
424
425 SHAPE_LINE_CHAIN& slc = line->Line();
426
427 if( shape->Contains( slc.CPoint( 0 ) ) )
428 clipLineToPad( slc, aPad, true );
429 else if( shape->Contains( slc.CPoint( -1 ) ) )
430 clipLineToPad( slc, aPad, false );
431 }
432 };
433
434 if( padA )
435 processPad( joints.first, padA );
436
437 if( padB )
438 processPad( joints.second, padB );
439
440 return initialPath;
441}
442
443
444const ITEM_SET TOPOLOGY::ConnectedItems( JOINT* aStart, int aKindMask )
445{
446 return ITEM_SET();
447}
448
449
450const ITEM_SET TOPOLOGY::ConnectedItems( ITEM* aStart, int aKindMask )
451{
452 return ITEM_SET();
453}
454
455
456bool commonParallelProjection( SEG p, SEG n, SEG &pClip, SEG& nClip );
457
458
460{
461 int refNet = aStart->Net();
462 int coupledNet = m_world->GetRuleResolver()->DpCoupledNet( refNet );
463
464 if( coupledNet < 0 )
465 return false;
466
467 std::set<ITEM*> coupledItems;
468
469 m_world->AllItemsInNet( coupledNet, coupledItems );
470
471 SEGMENT* coupledSeg = nullptr, *refSeg;
472 int minDist = std::numeric_limits<int>::max();
473
474 if( ( refSeg = dyn_cast<SEGMENT*>( aStart ) ) != nullptr )
475 {
476 for( ITEM* item : coupledItems )
477 {
478 if( SEGMENT* s = dyn_cast<SEGMENT*>( item ) )
479 {
480 if( s->Layers().Start() == refSeg->Layers().Start() &&
481 s->Width() == refSeg->Width() )
482 {
483 int dist = s->Seg().Distance( refSeg->Seg() );
484 bool isParallel = refSeg->Seg().ApproxParallel( s->Seg(), DP_PARALLELITY_THRESHOLD );
485 SEG p_clip, n_clip;
486
487 bool isCoupled = commonParallelProjection( refSeg->Seg(), s->Seg(), p_clip,
488 n_clip );
489
490 if( isParallel && isCoupled && dist < minDist )
491 {
492 minDist = dist;
493 coupledSeg = s;
494 }
495 }
496 }
497 }
498 }
499 else
500 {
501 return false;
502 }
503
504 if( !coupledSeg )
505 return false;
506
507 LINE lp = m_world->AssembleLine( refSeg );
508 LINE ln = m_world->AssembleLine( coupledSeg );
509
510 if( m_world->GetRuleResolver()->DpNetPolarity( refNet ) < 0 )
511 {
512 std::swap( lp, ln );
513 }
514
515 int gap = -1;
516
517 if( refSeg->Seg().ApproxParallel( coupledSeg->Seg(), DP_PARALLELITY_THRESHOLD ) )
518 {
519 // Segments are parallel -> compute pair gap
520 const VECTOR2I refDir = refSeg->Anchor( 1 ) - refSeg->Anchor( 0 );
521 const VECTOR2I displacement = refSeg->Anchor( 1 ) - coupledSeg->Anchor( 1 );
522 gap = (int) std::abs( refDir.Cross( displacement ) / refDir.EuclideanNorm() ) - lp.Width();
523 }
524
525 aPair = DIFF_PAIR( lp, ln );
526 aPair.SetWidth( lp.Width() );
527 aPair.SetLayers( lp.Layers() );
528 aPair.SetGap( gap );
529
530 return true;
531}
532
533const std::set<ITEM*> TOPOLOGY::AssembleCluster( ITEM* aStart, int aLayer )
534{
535 std::set<ITEM*> visited;
536 std::deque<ITEM*> pending;
537
538 pending.push_back( aStart );
539
540 while( !pending.empty() )
541 {
542 NODE::OBSTACLES obstacles;
543 ITEM* top = pending.front();
544
545 pending.pop_front();
546
547 visited.insert( top );
548
549 m_world->QueryColliding( top, obstacles, ITEM::ANY_T, -1, false, 0 ); // only query touching objects
550
551 for( OBSTACLE& obs : obstacles )
552 {
553 bool trackOnTrack = ( obs.m_item->Net() != top->Net() ) && obs.m_item->OfKind( ITEM::SEGMENT_T ) && top->OfKind( ITEM::SEGMENT_T );
554
555 if( trackOnTrack )
556 continue;
557
558 if( visited.find( obs.m_item ) == visited.end() &&
559 obs.m_item->Layers().Overlaps( aLayer ) && !( obs.m_item->Marker() & MK_HEAD ) )
560 {
561 visited.insert( obs.m_item );
562 pending.push_back( obs.m_item );
563 }
564 }
565 }
566
567 return visited;
568}
569
570}
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:58
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:97
Represent a contiguous set of PCB layers.
Definition: pns_layerset.h:32
Definition: pad.h:59
Basic class for a differential pair.
void SetGap(int aGap)
void SetWidth(int aWidth)
int Size() const
Definition: pns_itemset.h:160
void Add(const LINE &aLine)
Definition: pns_itemset.cpp:32
ENTRIES & Items()
Definition: pns_itemset.h:135
void Prepend(const LINE &aLine)
Definition: pns_itemset.cpp:39
Base class for PNS router board items.
Definition: pns_item.h:56
void SetLayers(const LAYER_RANGE &aLayers)
Definition: pns_item.h:157
PnsKind Kind() const
Return the type (kind) of the item.
Definition: pns_item.h:132
virtual int Layer() const
Definition: pns_item.h:160
@ SOLID_T
Definition: pns_item.h:63
@ LINE_T
Definition: pns_item.h:64
@ SEGMENT_T
Definition: pns_item.h:66
const LAYER_RANGE & Layers() const
Definition: pns_item.h:156
bool OfKind(int aKindMask) const
Return true if the item's type matches the mask aKindMask.
Definition: pns_item.h:140
virtual VECTOR2I Anchor(int n) const
Definition: pns_item.h:219
int Net() const
Definition: pns_item.h:154
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:43
int LinkCount(int aMask=-1) const
Definition: pns_joint.h:256
const LINKED_ITEMS & LinkList() const
Definition: pns_joint.h:241
ITEM_SET & Links()
Definition: pns_joint.h:251
int Net() const
Definition: pns_joint.h:236
bool IsNonFanoutVia() const
Definition: pns_joint.h:158
bool IsTraceWidthChange() const
Link the joint to a given board item (when it's added to the NODE).
Definition: pns_joint.h:172
const VECTOR2I & Pos() const
Definition: pns_joint.h:231
Represents a track on a PCB, connecting two non-trivial joints (that is, vias, pads,...
Definition: pns_line.h:61
const VECTOR2I & CPoint(int aIdx) const
Definition: pns_line.h:150
void SetShape(const SHAPE_LINE_CHAIN &aLine)
Return the shape of the line.
Definition: pns_line.h:126
const SHAPE_LINE_CHAIN & CLine() const
Definition: pns_line.h:142
SHAPE_LINE_CHAIN & Line()
Definition: pns_line.h:141
void Reverse()
Clip the line to the nearest obstacle, traversing from the line's start vertex (0).
Definition: pns_line.cpp:1023
int SegmentCount() const
Definition: pns_line.h:144
int PointCount() const
Definition: pns_line.h:145
bool EndsWithVia() const
Definition: pns_line.h:194
int Width() const
Return true if the line is geometrically identical as line aOther.
Definition: pns_line.h:161
NODE * Branch()
Create a lightweight copy (called branch) of self that tracks the changes (added/removed items) wrs t...
Definition: pns_node.cpp:139
int QueryColliding(const ITEM *aItem, OBSTACLES &aObstacles, int aKindMask=ITEM::ANY_T, int aLimitCount=-1, bool aDifferentNetsOnly=true, int aOverrideClearance=-1)
Find items colliding (closer than clearance) with the item aItem.
Definition: pns_node.cpp:271
void AllItemsInNet(int aNet, std::set< ITEM * > &aItems, int aKindMask=-1)
Definition: pns_node.cpp:1473
RULE_RESOLVER * GetRuleResolver() const
Return the number of joints.
Definition: pns_node.h:197
std::vector< OBSTACLE > OBSTACLES
Definition: pns_node.h:168
bool Add(std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant=false)
Add an item to the current node.
Definition: pns_node.cpp:664
JOINT * FindJoint(const VECTOR2I &aPos, int aLayer, int aNet)
Search for a joint at a given position, layer and belonging to given net.
Definition: pns_node.cpp:1197
void Remove(ARC *aArc)
Remove an item from this branch.
Definition: pns_node.cpp:889
const LINE AssembleLine(LINKED_ITEM *aSeg, int *aOriginSegmentIndex=nullptr, bool aStopAtLockedJoints=false, bool aFollowLockedSegments=false)
Follow the joint map to assemble a line connecting two non-trivial joints starting from segment aSeg.
Definition: pns_node.cpp:999
virtual int DpNetPolarity(int aNet)=0
virtual int DpCoupledNet(int aNet)=0
const SEG & Seg() const
Definition: pns_segment.h:84
virtual VECTOR2I Anchor(int n) const override
Definition: pns_segment.h:107
bool LeadingRatLine(const LINE *aTrack, SHAPE_LINE_CHAIN &aRatLine)
const DIFF_PAIR AssembleDiffPair(SEGMENT *aStart)
bool NearestUnconnectedAnchorPoint(const LINE *aTrack, VECTOR2I &aPoint, LAYER_RANGE &aLayers)
const ITEM_SET ConnectedItems(JOINT *aStart, int aKindMask=ITEM::ANY_T)
ITEM * NearestUnconnectedItem(JOINT *aStart, int *aAnchor=nullptr, int aKindMask=ITEM::ANY_T)
bool followTrivialPath(LINE *aLine, bool aLeft, ITEM_SET &aSet, std::set< ITEM * > &aVisited, JOINT **aTerminalJoint=nullptr)
const JOINT_SET ConnectedJoints(JOINT *aStart)
std::set< JOINT * > JOINT_SET
Definition: pns_topology.h:42
const ITEM_SET AssembleTrivialPath(ITEM *aStart, std::pair< JOINT *, JOINT * > *aTerminalJoints=nullptr, bool aFollowLockedSegments=false)
Assemble a trivial path between two joints given a starting item.
const int DP_PARALLELITY_THRESHOLD
Definition: pns_topology.h:96
const std::set< ITEM * > AssembleCluster(ITEM *aStart, int aLayer)
bool SimplifyLine(LINE *aLine)
const ITEM_SET AssembleTuningPath(ITEM *aStart, SOLID **aStartPad=nullptr, SOLID **aEndPad=nullptr)
Like AssembleTrivialPath, but follows the track length algorithm, which discards segments that are fu...
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
VECTOR2I B
Definition: seg.h:50
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
SHAPE_LINE_CHAIN & Simplify(bool aRemoveColinear=true)
Simplify the line chain by removing colinear adjacent segments and duplicate vertices.
virtual const VECTOR2I GetPoint(int aIndex) const override
int PointCount() const
Return the number of points (vertices) in this line chain.
void Replace(int aStartIndex, int aEndIndex, const VECTOR2I &aP)
Replace points with indices in range [start_index, end_index] with a single point aP.
void Clear()
Remove all points from the line chain.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
const VECTOR2I & CPoint(int aIndex) const
Return a reference to a given point in the line chain.
void Remove(int aStartIndex, int aEndIndex)
Remove the range of points [start_index, end_index] from the line chain.
void Insert(size_t aVertex, const VECTOR2I &aP)
const std::vector< VECTOR2I > & CPoints() const
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition: vector2d.h:293
extended_type Cross(const VECTOR2< T > &aVector) const
Compute cross product of self with aVector.
Definition: vector2d.h:487
Push and Shove diff pair dimensions (gap) settings dialog.
bool commonParallelProjection(SEG p, SEG n, SEG &pClip, SEG &nClip)
@ MK_HEAD
Definition: pns_item.h:41
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
CITER next(CITER it)
Definition: ptree.cpp:126
Hold an object colliding with another object, along with some useful data about the collision.
Definition: pns_node.h:113
constexpr int delta
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:129
@ PCB_PAD_T
class PAD, a pad in a footprint
Definition: typeinfo.h:87