static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) { bool found = false; for( int s = 0; s < aB.SegmentCount(); s++ ) { if( aA.Collide( aB.CSegment( s ), aClearance ) ) { found = true; break; } } if( !aNeedMTV || !found ) return found; SHAPE_CIRCLE cmoved( aA ); VECTOR2I f_total( 0, 0 ); for( int s = 0; s < aB.SegmentCount(); s++ ) { VECTOR2I f = pushoutForce( cmoved, aB.CSegment( s ), aClearance ); cmoved.SetCenter( cmoved.GetCenter() + f ); f_total += f; } aMTV = f_total; return found; }
SHAPE_LINE_CHAIN dragCornerInternal( const SHAPE_LINE_CHAIN& aOrigin, const VECTOR2I& aP ) { optional<SHAPE_LINE_CHAIN> picked; int i; int d = 2; if( aOrigin.CSegment( -1 ).Length() > 100000 * 30 ) // fixme: constant/parameter? d = 1; for( i = aOrigin.SegmentCount() - d; i >= 0; i-- ) { DIRECTION_45 d_start ( aOrigin.CSegment( i ) ); VECTOR2I p_start = aOrigin.CPoint( i ); SHAPE_LINE_CHAIN paths[2]; DIRECTION_45 dirs[2]; DIRECTION_45 d_prev = ( i > 0 ? DIRECTION_45( aOrigin.CSegment( i - 1 ) ) : DIRECTION_45() ); for( int j = 0; j < 2; j++ ) { paths[j] = d_start.BuildInitialTrace( p_start, aP, j ); dirs[j] = DIRECTION_45( paths[j].CSegment( 0 ) ); } for( int j = 0; j < 2; j++ ) { if( dirs[j] == d_start ) { picked = paths[j]; break; } } if( picked ) break; for( int j = 0; j < 2; j++ ) { if( dirs[j].IsObtuse( d_prev ) ) { picked = paths[j]; break; } } if( picked ) break; } if( picked ) { SHAPE_LINE_CHAIN path = aOrigin.Slice( 0, i ); path.Append( *picked ); return path; } return DIRECTION_45().BuildInitialTrace( aOrigin.CPoint( 0 ), aP, true ); }
void ROUTER_PREVIEW_ITEM::drawLineChain( const SHAPE_LINE_CHAIN& aL, KIGFX::GAL* aGal ) const { for( int s = 0; s < aL.SegmentCount(); s++ ) aGal->DrawLine( aL.CSegment( s ).A, aL.CSegment( s ).B ); if( aL.IsClosed() ) aGal->DrawLine( aL.CSegment( -1 ).B, aL.CSegment( 0 ).A ); }
bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd ) { SHAPE_LINE_CHAIN& head = m_head.Line(); SHAPE_LINE_CHAIN& tail = m_tail.Line(); int n = tail.SegmentCount(); if( head.SegmentCount() < 1 ) return false; // Don't attempt this for too short tails if( n < 2 ) return false; // Start from the segment farthest from the end of the tail // int start_index = std::max(n - 1 - ReductionDepth, 0); DIRECTION_45 new_direction; VECTOR2I new_start; int reduce_index = -1; for( int i = tail.SegmentCount() - 1; i >= 0; i-- ) { const SEG s = tail.CSegment( i ); DIRECTION_45 dir( s ); // calculate a replacement route and check if it matches // the direction of the segment to be replaced SHAPE_LINE_CHAIN replacement = dir.BuildInitialTrace( s.A, aEnd ); PNS_LINE tmp( m_tail, replacement ); if( m_currentNode->CheckColliding( &tmp, PNS_ITEM::ANY ) ) break; if( DIRECTION_45( replacement.CSegment( 0 ) ) == dir ) { new_start = s.A; new_direction = dir; reduce_index = i; } } if( reduce_index >= 0 ) { TRACE( 0, "Placer: reducing tail: %d", reduce_index ); SHAPE_LINE_CHAIN reducedLine = new_direction.BuildInitialTrace( new_start, aEnd ); m_p_start = new_start; m_direction = new_direction; tail.Remove( reduce_index + 1, -1 ); head.Clear(); return true; } if( !tail.SegmentCount() ) m_direction = m_initial_direction; return false; }
const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance, int aWalkaroundThickness ) { int d = aSeg.GetWidth() / 2 + aClearance + aWalkaroundThickness / 2 + HULL_MARGIN; int x = (int)( 2.0 / ( 1.0 + M_SQRT2 ) * d ); const VECTOR2I a = aSeg.GetSeg().A; const VECTOR2I b = aSeg.GetSeg().B; VECTOR2I dir = b - a; VECTOR2I p0 = dir.Perpendicular().Resize( d ); VECTOR2I ds = dir.Perpendicular().Resize( x / 2 ); VECTOR2I pd = dir.Resize( x / 2 ); VECTOR2I dp = dir.Resize( d ); SHAPE_LINE_CHAIN s; s.SetClosed( true ); s.Append( b + p0 + pd ); s.Append( b + dp + ds ); s.Append( b + dp - ds ); s.Append( b - p0 + pd ); s.Append( a - p0 - pd ); s.Append( a - dp - ds ); s.Append( a - dp + ds ); s.Append( a + p0 - pd ); // make sure the hull outline is always clockwise if( s.CSegment( 0 ).Side( a ) < 0 ) return s.Reverse(); else return s; }
static bool checkGap( const SHAPE_LINE_CHAIN &p, const SHAPE_LINE_CHAIN &n, int gap ) { int i, j; for( i = 0; i < p.SegmentCount(); i++ ) { for( j = 0; j < n.SegmentCount() ; j++ ) { int dist = p.CSegment( i ).Distance( n.CSegment( j ) ); if( dist < gap - 100 ) return false; } } return true; }
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 }
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) { for( int i = 0; i < aB.SegmentCount(); i++ ) if( aA.Collide( aB.CSegment( i ), aClearance ) ) return true; return false; }
VECTOR2I PNS_LINE::snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP, int aIndex, int aThreshold ) const { VECTOR2I snap_p[2]; DIRECTION_45 dragDir( aPath.CSegment( aIndex ) ); int snap_d[2] = { -1, -1 }; if( aThreshold == 0 ) return aP; if( aIndex >= 2 ) { SEG s = aPath.CSegment( aIndex - 2 ); if( DIRECTION_45( s ) == dragDir ) snap_d[0] = s.LineDistance( aP ); snap_p[0] = s.A; } if( aIndex < aPath.SegmentCount() - 2 ) { SEG s = aPath.CSegment( aIndex + 2 ); if( DIRECTION_45( s ) == dragDir ) snap_d[1] = s.LineDistance(aP); snap_p[1] = s.A; } VECTOR2I best = aP; int minDist = INT_MAX; for( int i = 0; i < 2; i++ ) { if( snap_d[i] >= 0 && snap_d[i] < minDist && snap_d[i] <= aThreshold ) { minDist = snap_d[i]; best = snap_p[i]; } } return best; }
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV ) { for( int s = 0; s < aB.SegmentCount(); s++ ) { if( aA.Collide( aB.CSegment( s ), aClearance ) ) return true; } return false; }
VECTOR2I PNS_LINE::snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, int aIndex, int aThreshold ) const { int s_start = std::max( aIndex - 2, 0 ); int s_end = std::min( aIndex + 2, aPath.SegmentCount() - 1 ); int i, j; int best_dist = INT_MAX; VECTOR2I best_snap = aP; if( aThreshold <= 0 ) return aP; for( i = s_start; i <= s_end; i++ ) { const SEG& a = aPath.CSegment( i ); for( j = s_start; j < i; j++ ) { const SEG& b = aPath.CSegment( j ); if( !( DIRECTION_45( a ).IsObtuse(DIRECTION_45( b ) ) ) ) continue; OPT_VECTOR2I ip = a.IntersectLines(b); if( ip ) { int dist = ( *ip - aP ).EuclideanNorm(); if( dist < aThreshold && dist < best_dist ) { best_dist = dist; best_snap = *ip; } } } } return best_snap; }
int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, INTERSECTIONS& aIp ) const { BOX2I bb_other = aChain.BBox(); for( int s1 = 0; s1 < SegmentCount(); s1++ ) { const SEG& a = CSegment( s1 ); const BOX2I bb_cur( a.A, a.B - a.A ); if( !bb_other.Intersects( bb_cur ) ) continue; for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ ) { const SEG& b = aChain.CSegment( s2 ); INTERSECTION is; if( a.Collinear( b ) ) { is.our = a; is.their = b; if( a.Contains( b.A ) ) { is.p = b.A; aIp.push_back( is ); } if( a.Contains( b.B ) ) { is.p = b.B; aIp.push_back( is ); } if( b.Contains( a.A ) ) { is.p = a.A; aIp.push_back( is ); } if( b.Contains( a.B ) ) { is.p = a.B; aIp.push_back( is ); } } else { OPT_VECTOR2I p = a.Intersect( b ); if( p ) { is.p = *p; is.our = a; is.their = b; aIp.push_back( is ); } } } } return aIp.size(); }