bool PNS_LINE_PLACER::buildInitialLine( const VECTOR2I& aP, PNS_LINE& aHead ) { SHAPE_LINE_CHAIN l; if( m_p_start == aP ) { l.Clear(); } else { if( Settings().GetFreeAngleMode() && Settings().Mode() == RM_MarkObstacles ) { l = SHAPE_LINE_CHAIN( m_p_start, aP ); } else { l = m_direction.BuildInitialTrace( m_p_start, aP ); } if( l.SegmentCount() > 1 && m_orthoMode ) { VECTOR2I newLast = l.CSegment( 0 ).LineProject( l.CPoint( -1 ) ); l.Remove( -1, -1 ); l.Point( 1 ) = newLast; } } aHead.SetShape( l ); if( !m_placingVia ) return true; PNS_VIA v( makeVia( aP ) ); v.SetNet( aHead.Net() ); if( m_currentMode == RM_MarkObstacles ) { aHead.AppendVia( v ); return true; } VECTOR2I force; VECTOR2I lead = aP - m_p_start; bool solidsOnly = ( m_currentMode != RM_Walkaround ); if( v.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) ) { SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP + force ); aHead = PNS_LINE( aHead, line ); v.SetPos( v.Pos() + force ); return true; } return false; // via placement unsuccessful }
PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath, bool aOptimize ) { PNS_LINE path_cw( aInitialPath ), path_ccw( aInitialPath ); WalkaroundStatus s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; SHAPE_LINE_CHAIN best_path; start( aInitialPath ); m_currentObstacle[0] = m_currentObstacle[1] = nearestObstacle( aInitialPath ); m_recursiveBlockageCount = 0; aWalkPath = aInitialPath; while( m_iteration < m_iteration_limit ) { if( s_cw != STUCK ) s_cw = singleStep( path_cw, true ); if( s_ccw != STUCK ) s_ccw = singleStep( path_ccw, false ); if( ( s_cw == DONE && s_ccw == DONE ) || ( s_cw == STUCK && s_ccw == STUCK ) ) { int len_cw = path_cw.GetCLine().Length(); int len_ccw = path_ccw.GetCLine().Length(); if( m_forceLongerPath ) aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); else aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); break; } else if( s_cw == DONE && !m_forceLongerPath ) { aWalkPath = path_cw; break; } else if( s_ccw == DONE && !m_forceLongerPath ) { aWalkPath = path_ccw; break; } m_iteration++; } if( m_iteration == m_iteration_limit ) { int len_cw = path_cw.GetCLine().Length(); int len_ccw = path_ccw.GetCLine().Length(); if( m_forceLongerPath ) aWalkPath = (len_cw > len_ccw ? path_cw : path_ccw); else aWalkPath = (len_cw < len_ccw ? path_cw : path_ccw); } if( m_cursorApproachMode ) { // int len_cw = path_cw.GetCLine().Length(); // int len_ccw = path_ccw.GetCLine().Length(); bool found = false; SHAPE_LINE_CHAIN l = aWalkPath.GetCLine(); for( int i = 0; i < l.SegmentCount(); i++ ) { const SEG s = l.Segment( i ); VECTOR2I nearest = s.NearestPoint( m_cursorPos ); VECTOR2I::extended_type dist_a = ( s.A - m_cursorPos ).SquaredEuclideanNorm(); VECTOR2I::extended_type dist_b = ( s.B - m_cursorPos ).SquaredEuclideanNorm(); VECTOR2I::extended_type dist_n = ( nearest - m_cursorPos ).SquaredEuclideanNorm(); if( dist_n <= dist_a && dist_n < dist_b ) { // PNSDisplayDebugLine( l, 3 ); l.Remove( i + 1, -1 ); l.Append( nearest ); l.Simplify(); found = true; break; } } if( found ) { aWalkPath = aInitialPath; aWalkPath.SetShape( l ); } } aWalkPath.SetWorld( m_world ); aWalkPath.GetLine().Simplify(); WalkaroundStatus st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; if( aOptimize && st == DONE ) PNS_OPTIMIZER::Optimize( &aWalkPath, PNS_OPTIMIZER::MERGE_OBTUSE, m_world ); return st; }
WALKAROUND::WALKAROUND_STATUS WALKAROUND::Route( const LINE& aInitialPath, LINE& aWalkPath, bool aOptimize ) { LINE path_cw( aInitialPath ), path_ccw( aInitialPath ); WALKAROUND_STATUS s_cw = IN_PROGRESS, s_ccw = IN_PROGRESS; SHAPE_LINE_CHAIN best_path; // special case for via-in-the-middle-of-track placement if( aInitialPath.PointCount() <= 1 ) { if( aInitialPath.EndsWithVia() && m_world->CheckColliding( &aInitialPath.Via(), m_itemMask ) ) return STUCK; aWalkPath = aInitialPath; return DONE; } start( aInitialPath ); m_currentObstacle[0] = m_currentObstacle[1] = nearestObstacle( aInitialPath ); m_recursiveBlockageCount = 0; aWalkPath = aInitialPath; if( m_forceWinding ) { s_cw = m_forceCw ? IN_PROGRESS : STUCK; s_ccw = m_forceCw ? STUCK : IN_PROGRESS; m_forceSingleDirection = true; } else { m_forceSingleDirection = false; } while( m_iteration < m_iterationLimit ) { if( s_cw != STUCK ) s_cw = singleStep( path_cw, true ); if( s_ccw != STUCK ) s_ccw = singleStep( path_ccw, false ); if( ( s_cw == DONE && s_ccw == DONE ) || ( s_cw == STUCK && s_ccw == STUCK ) ) { int len_cw = path_cw.CLine().Length(); int len_ccw = path_ccw.CLine().Length(); if( m_forceLongerPath ) aWalkPath = ( len_cw > len_ccw ? path_cw : path_ccw ); else aWalkPath = ( len_cw < len_ccw ? path_cw : path_ccw ); break; } else if( s_cw == DONE && !m_forceLongerPath ) { aWalkPath = path_cw; break; } else if( s_ccw == DONE && !m_forceLongerPath ) { aWalkPath = path_ccw; break; } m_iteration++; } if( m_iteration == m_iterationLimit ) { int len_cw = path_cw.CLine().Length(); int len_ccw = path_ccw.CLine().Length(); if( m_forceLongerPath ) aWalkPath = ( len_cw > len_ccw ? path_cw : path_ccw ); else aWalkPath = ( len_cw < len_ccw ? path_cw : path_ccw ); } if( m_cursorApproachMode ) { // int len_cw = path_cw.GetCLine().Length(); // int len_ccw = path_ccw.GetCLine().Length(); bool found = false; SHAPE_LINE_CHAIN l = aWalkPath.CLine(); for( int i = 0; i < l.SegmentCount(); i++ ) { const SEG s = l.Segment( i ); VECTOR2I nearest = s.NearestPoint( m_cursorPos ); VECTOR2I::extended_type dist_a = ( s.A - m_cursorPos ).SquaredEuclideanNorm(); VECTOR2I::extended_type dist_b = ( s.B - m_cursorPos ).SquaredEuclideanNorm(); VECTOR2I::extended_type dist_n = ( nearest - m_cursorPos ).SquaredEuclideanNorm(); if( dist_n <= dist_a && dist_n < dist_b ) { l.Remove( i + 1, -1 ); l.Append( nearest ); l.Simplify(); found = true; break; } } if( found ) { aWalkPath = aInitialPath; aWalkPath.SetShape( l ); } } aWalkPath.Line().Simplify(); if( aWalkPath.SegmentCount() < 1 ) return STUCK; if( aWalkPath.CPoint( -1 ) != aInitialPath.CPoint( -1 ) ) return STUCK; if( aWalkPath.CPoint( 0 ) != aInitialPath.CPoint( 0 ) ) return STUCK; WALKAROUND_STATUS st = s_ccw == DONE || s_cw == DONE ? DONE : STUCK; if( st == DONE ) { if( aOptimize ) OPTIMIZER::Optimize( &aWalkPath, OPTIMIZER::MERGE_OBTUSE, m_world ); } return st; }
bool PNS_DIFF_PAIR_PLACER::FixRoute( const VECTOR2I& aP, PNS_ITEM* aEndItem ) { if( !m_fitOk ) return false; if( m_currentTrace.CP().SegmentCount() < 1 || m_currentTrace.CN().SegmentCount() < 1 ) return false; if( m_currentTrace.CP().SegmentCount() > 1 ) m_initialDiagonal = !DIRECTION_45( m_currentTrace.CP().CSegment( -2 ) ).IsDiagonal(); PNS_TOPOLOGY topo( m_lastNode ); if( !m_snapOnTarget && !m_currentTrace.EndsWithVias() ) { SHAPE_LINE_CHAIN newP ( m_currentTrace.CP() ); SHAPE_LINE_CHAIN newN ( m_currentTrace.CN() ); if( newP.SegmentCount() > 1 && newN.SegmentCount() > 1 ) { newP.Remove( -1, -1 ); newN.Remove( -1, -1 ); } m_currentTrace.SetShape( newP, newN ); } if( m_currentTrace.EndsWithVias() ) { m_lastNode->Add( m_currentTrace.PLine().Via().Clone() ); m_lastNode->Add( m_currentTrace.NLine().Via().Clone() ); m_chainedPlacement = false; } else m_chainedPlacement = !m_snapOnTarget; PNS_LINE lineP( m_currentTrace.PLine() ); PNS_LINE lineN( m_currentTrace.NLine() ); m_lastNode->Add( &lineP ); m_lastNode->Add( &lineN ); topo.SimplifyLine( &lineP ); topo.SimplifyLine( &lineN ); m_prevPair = m_currentTrace.EndingPrimitives(); Router()->CommitRouting( m_lastNode ); m_lastNode = NULL; m_placingVia = false; if( m_snapOnTarget ) { m_idle = true; return true; } else { initPlacement(); return false; } }
void PNS_LINE::DragSegment ( const VECTOR2I& aP, int aIndex, int aSnappingThreshold ) { SHAPE_LINE_CHAIN path( m_line ); VECTOR2I target( aP ); SEG guideA[2], guideB[2]; int index = aIndex; target = snapToNeighbourSegments( path, aP, aIndex, aSnappingThreshold ); if( index == 0 ) { path.Insert( 0, path.CPoint( 0 ) ); index++; } if( index == path.SegmentCount() - 1 ) { path.Insert( path.PointCount() - 1, path.CPoint( -1 ) ); } SEG dragged = path.CSegment( index ); DIRECTION_45 drag_dir( dragged ); SEG s_prev = path.CSegment( index - 1 ); SEG s_next = path.CSegment( index + 1 ); DIRECTION_45 dir_prev( s_prev ); DIRECTION_45 dir_next( s_next ); if( dir_prev == drag_dir ) { dir_prev = dir_prev.Left(); path.Insert( index, path.CPoint( index ) ); index++; } if( dir_next == drag_dir ) { dir_next = dir_next.Right(); path.Insert( index + 1, path.CPoint( index + 1 ) ); } s_prev = path.CSegment( index - 1 ); s_next = path.CSegment( index + 1 ); dragged = path.CSegment( index ); bool lockEndpointA = true; bool lockEndpointB = true; if( aIndex == 0 ) { if( !lockEndpointA ) guideA[0] = guideA[1] = SEG( dragged.A, dragged.A + drag_dir.Right().Right().ToVector() ); else { guideA[0] = SEG( dragged.A, dragged.A + drag_dir.Right().ToVector() ); guideA[1] = SEG( dragged.A, dragged.A + drag_dir.Left().ToVector() ); } } else { if( dir_prev.IsObtuse(drag_dir ) ) { guideA[0] = SEG( s_prev.A, s_prev.A + drag_dir.Left().ToVector() ); guideA[1] = SEG( s_prev.A, s_prev.A + drag_dir.Right().ToVector() ); } else guideA[0] = guideA[1] = SEG( dragged.A, dragged.A + dir_prev.ToVector() ); } if( aIndex == m_line.SegmentCount() - 1 ) { if( !lockEndpointB ) guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + drag_dir.Right().Right().ToVector() ); else { guideB[0] = SEG( dragged.B, dragged.B + drag_dir.Right().ToVector() ); guideB[1] = SEG( dragged.B, dragged.B + drag_dir.Left().ToVector() ); } } else { if( dir_next.IsObtuse( drag_dir ) ) { guideB[0] = SEG( s_next.B, s_next.B + drag_dir.Left().ToVector() ); guideB[1] = SEG( s_next.B, s_next.B + drag_dir.Right().ToVector() ); } else guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + dir_next.ToVector() ); } SEG s_current( target, target + drag_dir.ToVector() ); int best_len = INT_MAX; SHAPE_LINE_CHAIN best; for( int i = 0; i < 2; i++ ) { for( int j = 0; j < 2; j++ ) { OPT_VECTOR2I ip1 = s_current.IntersectLines( guideA[i] ); OPT_VECTOR2I ip2 = s_current.IntersectLines( guideB[j] ); SHAPE_LINE_CHAIN np; if( !ip1 || !ip2 ) continue; SEG s1( s_prev.A, *ip1 ); SEG s2( *ip1, *ip2 ); SEG s3( *ip2, s_next.B ); OPT_VECTOR2I ip; if( (ip = s1.Intersect( s_next )) ) { np.Append ( s1.A ); np.Append ( *ip ); np.Append ( s_next.B ); } else if( (ip = s3.Intersect( s_prev )) ) { np.Append ( s_prev.A ); np.Append ( *ip ); np.Append ( s3.B ); } else if( (ip = s1.Intersect( s3 )) ) { np.Append( s_prev.A ); np.Append( *ip ); np.Append( s_next.B ); } else { np.Append( s_prev.A ); np.Append( *ip1 ); np.Append( *ip2 ); np.Append( s_next.B ); } if( np.Length() < best_len ) { best_len = np.Length(); best = np; } } } if( !lockEndpointA && aIndex == 0 ) best.Remove( 0, 0 ); if( !lockEndpointB && aIndex == m_line.SegmentCount() - 1 ) best.Remove( -1, -1 ); if( m_line.PointCount() == 1 ) m_line = best; else if( aIndex == 0 ) m_line.Replace( 0, 1, best ); else if( aIndex == m_line.SegmentCount() - 1 ) m_line.Replace( -2, -1, best ); else m_line.Replace( aIndex, aIndex + 1, best ); m_line.Simplify(); }