kicad/pcbnew/router/pns_via.cpp

162 lines
4.1 KiB
C++

/*
* KiRouter - a push-and-(sometimes-)shove PCB router
*
* Copyright (C) 2013 CERN
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.or/licenses/>.
*/
#include "pns_via.h"
#include "pns_node.h"
#include "pns_utils.h"
#include <geometry/shape_rect.h>
static bool Circle2Circle( VECTOR2I p1, VECTOR2I p2, int r1, int r2, VECTOR2I& force )
{
int mindist = r1 + r2;
VECTOR2I delta = p2 - p1;
int dist = delta.EuclideanNorm();
if( dist >= mindist )
return false;
force = delta.Resize( abs( mindist - dist ) + 1 );
return true;
};
static bool Rect2Circle( VECTOR2I rp0, VECTOR2I rsize, VECTOR2I cc, int cr, VECTOR2I& force )
{
VECTOR2I vts[] =
{
VECTOR2I( rp0.x, rp0.y ),
VECTOR2I( rp0.x, rp0.y + rsize.y ),
VECTOR2I( rp0.x + rsize.x, rp0.y + rsize.y ),
VECTOR2I( rp0.x + rsize.x, rp0.y ),
VECTOR2I( rp0.x, rp0.y )
};
int dist = INT_MAX;
VECTOR2I nearest;
for( int i = 0; i < 4; i++ )
{
SEG s( vts[i], vts[i + 1] );
VECTOR2I pn = s.NearestPoint( cc );
int d = (pn - cc).EuclideanNorm();
if( d < dist )
{
nearest = pn;
dist = d;
}
}
bool inside = cc.x >= rp0.x && cc.x <= (rp0.x + rsize.x)
&& cc.y >= rp0.y && cc.y <= (rp0.y + rsize.y);
VECTOR2I delta = cc - nearest;
if( dist >= cr && !inside )
return false;
if( inside )
force = -delta.Resize( abs( cr + dist ) + 1 );
else
force = delta.Resize( abs( cr - dist ) + 1 );
return true;
};
static bool ShPushoutForce( const SHAPE* shape, VECTOR2I p, int r, VECTOR2I& force, int clearance )
{
switch( shape->Type() )
{
case SH_CIRCLE:
{
const SHAPE_CIRCLE* cir = static_cast<const SHAPE_CIRCLE*>(shape);
return Circle2Circle( cir->GetCenter(), p, cir->GetRadius(), r + clearance + 1, force );
}
case SH_RECT:
{
const SHAPE_RECT* rect = static_cast<const SHAPE_RECT*>(shape);
return Rect2Circle( rect->GetPosition(), rect->GetSize(), p, r + clearance + 1, force );
}
default:
return false;
}
return false;
}
bool PNS_VIA::PushoutForce( PNS_NODE* aNode,
const VECTOR2I& aDirection,
VECTOR2I& aForce,
bool aSolidsOnly,
int aMaxIterations )
{
int iter = 0;
PNS_VIA mv( *this );
VECTOR2I force, totalForce;
while( iter < aMaxIterations )
{
PNS_NODE::OptObstacle obs = aNode->CheckColliding( &mv,
aSolidsOnly ? PNS_ITEM::SOLID : PNS_ITEM::ANY );
if( !obs )
break;
int clearance = aNode->GetClearance( obs->item, &mv );
if( iter > 10 )
{
VECTOR2I l = -aDirection.Resize( m_diameter / 4 );
totalForce += l;
mv.SetPos( mv.GetPos() + l );
}
if( ShPushoutForce( obs->item->GetShape(), mv.GetPos(), mv.GetDiameter() / 2, force,
clearance ) )
{
totalForce += force;
mv.SetPos( mv.GetPos() + force );
}
iter++;
}
if( iter == aMaxIterations )
return false;
aForce = totalForce;
return true;
}
const SHAPE_LINE_CHAIN PNS_VIA::Hull( int aClearance, int aWalkaroundThickness ) const
{
return OctagonalHull( m_pos -
VECTOR2I( m_diameter / 2, m_diameter / 2 ), VECTOR2I( m_diameter,
m_diameter ), aClearance + 1, (2 * aClearance + m_diameter) * 0.26 );
}