const PNS_TOPOLOGY::JOINT_SET PNS_TOPOLOGY::ConnectedJoints( PNS_JOINT* aStart ) { std::deque<PNS_JOINT*> searchQueue; JOINT_SET processed; searchQueue.push_back( aStart ); processed.insert( aStart ); while( !searchQueue.empty() ) { PNS_JOINT* current = searchQueue.front(); searchQueue.pop_front(); for( PNS_ITEM* item : current->LinkList() ) { if( item->OfKind( PNS_ITEM::SEGMENT ) ) { PNS_SEGMENT* seg = static_cast<PNS_SEGMENT*>( item ); PNS_JOINT* a = m_world->FindJoint( seg->Seg().A, seg ); PNS_JOINT* b = m_world->FindJoint( seg->Seg().B, seg ); PNS_JOINT* next = ( *a == *current ) ? b : a; if( processed.find( next ) == processed.end() ) { processed.insert( next ); searchQueue.push_back( next ); } } } } return processed; }
OPT_VECTOR2I PNS_DIFF_PAIR_PLACER::getDanglingAnchor( PNS_NODE* aNode, PNS_ITEM* aItem ) { switch( aItem->Kind() ) { case PNS_ITEM::VIA: case PNS_ITEM::SOLID: return aItem->Anchor( 0 ); case PNS_ITEM::SEGMENT: { PNS_SEGMENT* s =static_cast<PNS_SEGMENT*>( aItem ); PNS_JOINT* jA = aNode->FindJoint( s->Seg().A, s ); PNS_JOINT* jB = aNode->FindJoint( s->Seg().B, s ); if( jA->LinkCount() == 1 ) return s->Seg().A; else if( jB->LinkCount() == 1 ) return s->Seg().B; else return OPT_VECTOR2I(); } default: return OPT_VECTOR2I(); break; } }
bool PNS_TOPOLOGY::followTrivialPath( PNS_LINE* aLine, bool aLeft, PNS_ITEMSET& aSet, std::set<PNS_ITEM*>& aVisited ) { VECTOR2I anchor = aLeft ? aLine->CPoint( 0 ) : aLine->CPoint( -1 ); PNS_SEGMENT* last = aLeft ? aLine->LinkedSegments()->front() : aLine->LinkedSegments()->back(); PNS_JOINT* jt = m_world->FindJoint( anchor, aLine ); assert( jt != NULL ); aVisited.insert( last ); if( jt->IsNonFanoutVia() || jt->IsTraceWidthChange() ) { PNS_ITEM* via = NULL; PNS_SEGMENT* next_seg = NULL; for( PNS_ITEM* link : jt->Links().Items() ) { if( link->OfKind( PNS_ITEM::VIA ) ) via = link; else if( aVisited.find( link ) == aVisited.end() ) next_seg = static_cast<PNS_SEGMENT*>( link ); } if( !next_seg ) return false; PNS_LINE l = m_world->AssembleLine( next_seg ); VECTOR2I nextAnchor = ( aLeft ? l.CLine().CPoint( -1 ) : l.CLine().CPoint( 0 ) ); if( nextAnchor != anchor ) { l.Reverse(); } if( aLeft ) { if( via ) aSet.Prepend( via ); aSet.Prepend( l ); } else { if( via ) aSet.Add( via ); aSet.Add( l ); } return followTrivialPath( &l, aLeft, aSet, aVisited ); } return false; }
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; }
void PNS_LINE_PLACER::splitAdjacentSegments( PNS_NODE* aNode, PNS_ITEM* aSeg, const VECTOR2I& aP ) { if( aSeg && aSeg->OfKind( PNS_ITEM::SEGMENT ) ) { PNS_JOINT* jt = aNode->FindJoint( aP, aSeg ); if( jt && jt->LinkCount() >= 1 ) return; PNS_SEGMENT* s_old = static_cast<PNS_SEGMENT*>( aSeg ); PNS_SEGMENT* s_new[2]; s_new[0] = s_old->Clone(); s_new[1] = s_old->Clone(); s_new[0]->SetEnds( s_old->Seg().A, aP ); s_new[1]->SetEnds( aP, s_old->Seg().B ); aNode->Remove( s_old ); aNode->Add( s_new[0], true ); aNode->Add( s_new[1], true ); } }