router: factor out POSTURE_SOLVER to more generic MOUSE_TRAIL_TRACER class
This commit is contained in:
parent
baacb9c85a
commit
f84836f51e
|
@ -29,6 +29,7 @@ set( PCBNEW_PNS_SRCS
|
||||||
pns_meander_placer.cpp
|
pns_meander_placer.cpp
|
||||||
pns_meander_placer_base.cpp
|
pns_meander_placer_base.cpp
|
||||||
pns_meander_skew_placer.cpp
|
pns_meander_skew_placer.cpp
|
||||||
|
pns_mouse_trail_tracer.cpp
|
||||||
pns_node.cpp
|
pns_node.cpp
|
||||||
pns_optimizer.cpp
|
pns_optimizer.cpp
|
||||||
pns_router.cpp
|
pns_router.cpp
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
#include "pns_solid.h"
|
#include "pns_solid.h"
|
||||||
#include "pns_topology.h"
|
#include "pns_topology.h"
|
||||||
#include "pns_walkaround.h"
|
#include "pns_walkaround.h"
|
||||||
|
#include "pns_mouse_trail_tracer.h"
|
||||||
|
|
||||||
namespace PNS {
|
namespace PNS {
|
||||||
|
|
||||||
|
@ -607,7 +607,7 @@ bool LINE_PLACER::rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead )
|
||||||
|
|
||||||
int effortLevel = OPTIMIZER::MERGE_OBTUSE;
|
int effortLevel = OPTIMIZER::MERGE_OBTUSE;
|
||||||
|
|
||||||
if( Settings().SmartPads() && !m_postureSolver.IsManuallyForced() )
|
if( Settings().SmartPads() && !m_mouseTrailTracer.IsManuallyForced() )
|
||||||
effortLevel = OPTIMIZER::SMART_PADS;
|
effortLevel = OPTIMIZER::SMART_PADS;
|
||||||
|
|
||||||
optimizer.SetEffortLevel( effortLevel );
|
optimizer.SetEffortLevel( effortLevel );
|
||||||
|
@ -803,7 +803,7 @@ const ITEM_SET LINE_PLACER::Traces()
|
||||||
|
|
||||||
void LINE_PLACER::FlipPosture()
|
void LINE_PLACER::FlipPosture()
|
||||||
{
|
{
|
||||||
m_postureSolver.FlipPosture();
|
m_mouseTrailTracer.FlipPosture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -912,11 +912,11 @@ bool LINE_PLACER::Start( const VECTOR2I& aP, ITEM* aStartItem )
|
||||||
|
|
||||||
wxLogTrace( "PNS", "Posture: init %s, last seg %s", initialDir.Format(), lastSegDir.Format() );
|
wxLogTrace( "PNS", "Posture: init %s, last seg %s", initialDir.Format(), lastSegDir.Format() );
|
||||||
|
|
||||||
m_postureSolver.Clear();
|
m_mouseTrailTracer.Clear();
|
||||||
m_postureSolver.AddTrailPoint( aP );
|
m_mouseTrailTracer.AddTrailPoint( aP );
|
||||||
m_postureSolver.SetTolerance( m_head.Width() );
|
m_mouseTrailTracer.SetTolerance( m_head.Width() );
|
||||||
m_postureSolver.SetDefaultDirections( initialDir, lastSegDir );
|
m_mouseTrailTracer.SetDefaultDirections( m_initial_direction, DIRECTION_45::UNDEFINED );
|
||||||
m_postureSolver.SetMouseDisabled( !Settings().GetAutoPosture() );
|
m_mouseTrailTracer.SetMouseDisabled( !Settings().GetAutoPosture() );
|
||||||
|
|
||||||
NODE *n;
|
NODE *n;
|
||||||
|
|
||||||
|
@ -1013,7 +1013,7 @@ bool LINE_PLACER::Move( const VECTOR2I& aP, ITEM* aEndItem )
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLeadingRatLine();
|
updateLeadingRatLine();
|
||||||
m_postureSolver.AddTrailPoint( aP );
|
m_mouseTrailTracer.AddTrailPoint( aP );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1169,10 +1169,10 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
|
||||||
|
|
||||||
DIRECTION_45 lastSegDir = pl.EndsWithVia() ? DIRECTION_45::UNDEFINED : d_last;
|
DIRECTION_45 lastSegDir = pl.EndsWithVia() ? DIRECTION_45::UNDEFINED : d_last;
|
||||||
|
|
||||||
m_postureSolver.Clear();
|
m_mouseTrailTracer.Clear();
|
||||||
m_postureSolver.SetTolerance( m_head.Width() );
|
m_mouseTrailTracer.SetTolerance( m_head.Width() );
|
||||||
m_postureSolver.AddTrailPoint( m_currentStart );
|
m_mouseTrailTracer.AddTrailPoint( m_currentStart );
|
||||||
m_postureSolver.SetDefaultDirections( m_initial_direction, lastSegDir );
|
m_mouseTrailTracer.SetDefaultDirections( m_initial_direction, lastSegDir );
|
||||||
|
|
||||||
m_placementCorrect = true;
|
m_placementCorrect = true;
|
||||||
}
|
}
|
||||||
|
@ -1206,9 +1206,9 @@ bool LINE_PLACER::UnfixRoute()
|
||||||
m_head.RemoveVia();
|
m_head.RemoveVia();
|
||||||
m_tail.RemoveVia();
|
m_tail.RemoveVia();
|
||||||
|
|
||||||
m_postureSolver.Clear();
|
m_mouseTrailTracer.Clear();
|
||||||
m_postureSolver.SetDefaultDirections( m_initial_direction, m_direction );
|
m_mouseTrailTracer.SetDefaultDirections( m_initial_direction, m_direction );
|
||||||
m_postureSolver.AddTrailPoint( m_p_start );
|
m_mouseTrailTracer.AddTrailPoint( m_p_start );
|
||||||
|
|
||||||
if( m_shove )
|
if( m_shove )
|
||||||
{
|
{
|
||||||
|
@ -1314,6 +1314,13 @@ void LINE_PLACER::simplifyNewLine( NODE* aNode, LINKED_ITEM* aLatest )
|
||||||
|
|
||||||
void LINE_PLACER::UpdateSizes( const SIZES_SETTINGS& aSizes )
|
void LINE_PLACER::UpdateSizes( const SIZES_SETTINGS& aSizes )
|
||||||
{
|
{
|
||||||
|
// initPlacement will kill the tail, don't do that unless the track size has changed
|
||||||
|
if( !m_idle && aSizes.TrackWidth() != m_sizes.TrackWidth() )
|
||||||
|
{
|
||||||
|
m_sizes = aSizes;
|
||||||
|
initPlacement();
|
||||||
|
}
|
||||||
|
|
||||||
m_sizes = aSizes;
|
m_sizes = aSizes;
|
||||||
|
|
||||||
if( !m_idle )
|
if( !m_idle )
|
||||||
|
@ -1350,7 +1357,7 @@ void LINE_PLACER::SetOrthoMode( bool aOrthoMode )
|
||||||
bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead )
|
bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead )
|
||||||
{
|
{
|
||||||
SHAPE_LINE_CHAIN l;
|
SHAPE_LINE_CHAIN l;
|
||||||
DIRECTION_45 guessedDir = m_postureSolver.GetPosture( aP );
|
DIRECTION_45 guessedDir = m_mouseTrailTracer.GetPosture( aP );
|
||||||
|
|
||||||
wxLogTrace( "PNS", "buildInitialLine: m_direction %s, guessedDir %s, tail points %d",
|
wxLogTrace( "PNS", "buildInitialLine: m_direction %s, guessedDir %s, tail points %d",
|
||||||
m_direction.Format(), guessedDir.Format(), m_tail.PointCount() );
|
m_direction.Format(), guessedDir.Format(), m_tail.PointCount() );
|
||||||
|
@ -1482,239 +1489,5 @@ int FIXED_TAIL::StageCount() const
|
||||||
return m_stages.size();
|
return m_stages.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
POSTURE_SOLVER::POSTURE_SOLVER()
|
|
||||||
{
|
|
||||||
m_tolerance = 0;
|
|
||||||
m_disableMouse = false;
|
|
||||||
Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
POSTURE_SOLVER::~POSTURE_SOLVER() {}
|
|
||||||
|
|
||||||
|
|
||||||
void POSTURE_SOLVER::Clear()
|
|
||||||
{
|
|
||||||
m_forced = false;
|
|
||||||
m_manuallyForced = false;
|
|
||||||
m_trail.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void POSTURE_SOLVER::AddTrailPoint( const VECTOR2I& aP )
|
|
||||||
{
|
|
||||||
if( m_trail.SegmentCount() == 0 )
|
|
||||||
{
|
|
||||||
m_trail.Append( aP );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SEG s_new( m_trail.CPoint( -1 ), aP );
|
|
||||||
|
|
||||||
for( int i = 0; i < m_trail.SegmentCount() - 1; i++ )
|
|
||||||
{
|
|
||||||
const SEG& s_trail = m_trail.CSegment( i );
|
|
||||||
|
|
||||||
if( s_trail.Distance( s_new ) <= m_tolerance )
|
|
||||||
{
|
|
||||||
m_trail = m_trail.Slice( 0, i );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
m_trail.Append( aP );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_trail.Simplify();
|
|
||||||
|
|
||||||
ROUTER::GetInstance()->GetInterface()->GetDebugDecorator()->AddLine( m_trail, 5, 100000 );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DIRECTION_45 POSTURE_SOLVER::GetPosture( const VECTOR2I& aP )
|
|
||||||
{
|
|
||||||
// Tuning factor for how good the "fit" of the trail must be to the posture
|
|
||||||
const double areaRatioThreshold = 1.3;
|
|
||||||
|
|
||||||
// Tuning factor to minimize flutter
|
|
||||||
const double areaRatioEpsilon = 0.25;
|
|
||||||
|
|
||||||
// Minimum distance factor of the trail before the min area test is used to lock the solver
|
|
||||||
const double minAreaCutoffDistanceFactor = 6;
|
|
||||||
|
|
||||||
// Adjusts how far away from p0 we get before whatever posture we solved is locked in
|
|
||||||
const int lockDistanceFactor = 25;
|
|
||||||
|
|
||||||
// Adjusts how close to p0 we unlock the posture again if one was locked already
|
|
||||||
const int unlockDistanceFactor = 4;
|
|
||||||
|
|
||||||
if( m_trail.PointCount() < 2 || m_manuallyForced )
|
|
||||||
{
|
|
||||||
// If mouse trail detection is enabled; using the last seg direction as a starting point
|
|
||||||
// will give the best results. Otherwise, just assume that we switch postures every
|
|
||||||
// segment.
|
|
||||||
if( !m_manuallyForced && m_lastSegDirection != DIRECTION_45::UNDEFINED )
|
|
||||||
m_direction = m_disableMouse ? m_lastSegDirection.Right() : m_lastSegDirection;
|
|
||||||
|
|
||||||
return m_direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_DECORATOR* dbg = ROUTER::GetInstance()->GetInterface()->GetDebugDecorator();
|
|
||||||
VECTOR2I p0 = m_trail.CPoint( 0 );
|
|
||||||
double refLength = SEG( p0, aP ).Length();
|
|
||||||
SHAPE_LINE_CHAIN straight( DIRECTION_45().BuildInitialTrace( p0, aP, false, false ) );
|
|
||||||
|
|
||||||
straight.SetClosed( true );
|
|
||||||
straight.Append( m_trail.Reverse() );
|
|
||||||
straight.Simplify();
|
|
||||||
dbg->AddLine( straight, m_forced ? 3 : 2, 100000 );
|
|
||||||
|
|
||||||
double areaS = std::abs( straight.Area() );
|
|
||||||
|
|
||||||
SHAPE_LINE_CHAIN diag( DIRECTION_45().BuildInitialTrace( p0, aP, true, false ) );
|
|
||||||
diag.Append( m_trail.Reverse() );
|
|
||||||
diag.SetClosed( true );
|
|
||||||
diag.Simplify();
|
|
||||||
dbg->AddLine( diag, 1, 100000 );
|
|
||||||
|
|
||||||
double areaDiag = std::abs( diag.Area() );
|
|
||||||
double ratio = areaS / ( areaDiag + 1.0 );
|
|
||||||
|
|
||||||
// heuristic to detect that the user dragged back the cursor to the beginning of the trace
|
|
||||||
// in this case, we cancel any forced posture and restart the trail
|
|
||||||
if( m_forced && refLength < unlockDistanceFactor * m_tolerance )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: Unlocked and reset" );
|
|
||||||
m_forced = false;
|
|
||||||
VECTOR2I start = p0;
|
|
||||||
m_trail.Clear();
|
|
||||||
m_trail.Append( start );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool areaOk = false;
|
|
||||||
|
|
||||||
// Check the actual trail area against the cutoff. This prevents flutter when the trail is
|
|
||||||
// very close to a straight line.
|
|
||||||
if( !m_forced && refLength > minAreaCutoffDistanceFactor * m_tolerance )
|
|
||||||
{
|
|
||||||
double areaCutoff = m_tolerance * refLength;
|
|
||||||
SHAPE_LINE_CHAIN trail( m_trail );
|
|
||||||
trail.SetClosed( true );
|
|
||||||
|
|
||||||
if( std::abs( trail.Area() ) > areaCutoff )
|
|
||||||
areaOk = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
DIRECTION_45 straightDirection;
|
|
||||||
DIRECTION_45 diagDirection;
|
|
||||||
DIRECTION_45 newDirection = m_direction;
|
|
||||||
|
|
||||||
straightDirection = DIRECTION_45( straight.CSegment( 0 ) );
|
|
||||||
diagDirection = DIRECTION_45( diag.CSegment( 0 ) );
|
|
||||||
|
|
||||||
if( !m_forced && areaOk && ratio > areaRatioThreshold + areaRatioEpsilon )
|
|
||||||
newDirection = diagDirection;
|
|
||||||
else if( !m_forced && areaOk && ratio < ( 1.0 / areaRatioThreshold ) - areaRatioEpsilon )
|
|
||||||
newDirection = straightDirection;
|
|
||||||
else
|
|
||||||
newDirection = m_direction.IsDiagonal() ? diagDirection : straightDirection;
|
|
||||||
|
|
||||||
if( !m_disableMouse && newDirection != m_direction )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: direction update %s => %s", m_direction.Format(),
|
|
||||||
newDirection.Format() );
|
|
||||||
m_direction = newDirection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a last segment, correct the direction relative to it. For segment exit, we want
|
|
||||||
// to correct to the least obtuse
|
|
||||||
if( !m_manuallyForced && !m_disableMouse && m_lastSegDirection != DIRECTION_45::UNDEFINED )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: checking direction %s against last seg %s",
|
|
||||||
m_direction.Format(), m_lastSegDirection.Format() );
|
|
||||||
|
|
||||||
if( straightDirection == m_lastSegDirection )
|
|
||||||
{
|
|
||||||
if( m_direction != straightDirection )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: forcing straight => %s", straightDirection.Format() );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_direction = straightDirection;
|
|
||||||
}
|
|
||||||
else if( diagDirection == m_lastSegDirection )
|
|
||||||
{
|
|
||||||
if( m_direction != diagDirection )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: forcing diagonal => %s", diagDirection.Format() );
|
|
||||||
}
|
|
||||||
|
|
||||||
m_direction = diagDirection;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch( m_direction.Angle( m_lastSegDirection ) )
|
|
||||||
{
|
|
||||||
case DIRECTION_45::ANG_HALF_FULL:
|
|
||||||
// Force a better (acute) connection
|
|
||||||
m_direction = m_direction.IsDiagonal() ? straightDirection : diagDirection;
|
|
||||||
wxLogTrace( "PNS", "Posture: correcting half full => %s", m_direction.Format() );
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DIRECTION_45::ANG_ACUTE:
|
|
||||||
{
|
|
||||||
// Force a better connection by flipping if possible
|
|
||||||
DIRECTION_45 candidate = m_direction.IsDiagonal() ? straightDirection
|
|
||||||
: diagDirection;
|
|
||||||
|
|
||||||
if( candidate.Angle( m_lastSegDirection ) == DIRECTION_45::ANG_RIGHT )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: correcting right => %s", candidate.Format() );
|
|
||||||
m_direction = candidate;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case DIRECTION_45::ANG_RIGHT:
|
|
||||||
{
|
|
||||||
// Force a better connection by flipping if possible
|
|
||||||
DIRECTION_45 candidate = m_direction.IsDiagonal() ? straightDirection
|
|
||||||
: diagDirection;
|
|
||||||
|
|
||||||
if( candidate.Angle( m_lastSegDirection ) == DIRECTION_45::ANG_OBTUSE )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: correcting obtuse => %s", candidate.Format() );
|
|
||||||
m_direction = candidate;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we get far away from the initial point, lock in the current solution to prevent flutter
|
|
||||||
if( !m_forced && refLength > lockDistanceFactor * m_tolerance )
|
|
||||||
{
|
|
||||||
wxLogTrace( "PNS", "Posture: solution locked" );
|
|
||||||
m_forced = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_direction;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void POSTURE_SOLVER::FlipPosture()
|
|
||||||
{
|
|
||||||
m_direction = m_direction.Right();
|
|
||||||
m_forced = true;
|
|
||||||
m_manuallyForced = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "pns_via.h"
|
#include "pns_via.h"
|
||||||
#include "pns_line.h"
|
#include "pns_line.h"
|
||||||
#include "pns_placement_algo.h"
|
#include "pns_placement_algo.h"
|
||||||
|
#include "pns_mouse_trail_tracer.h"
|
||||||
|
|
||||||
namespace PNS {
|
namespace PNS {
|
||||||
|
|
||||||
|
@ -74,50 +75,10 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class POSTURE_SOLVER
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
POSTURE_SOLVER();
|
|
||||||
~POSTURE_SOLVER();
|
|
||||||
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
void AddTrailPoint( const VECTOR2I& aP );
|
|
||||||
|
|
||||||
void SetTolerance( int toll ) { m_tolerance = toll; }
|
|
||||||
|
|
||||||
void SetDefaultDirections( DIRECTION_45 aInitDirection, DIRECTION_45 aLastSegDir )
|
|
||||||
{
|
|
||||||
m_direction = aInitDirection;
|
|
||||||
m_lastSegDirection = aLastSegDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
DIRECTION_45 GetPosture( const VECTOR2I& aP );
|
|
||||||
|
|
||||||
void FlipPosture();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable the mouse-trail portion of the posture solver; leaving only the manual posture
|
|
||||||
* switch and the previous-segment posture algorithm
|
|
||||||
*/
|
|
||||||
void SetMouseDisabled( bool aDisabled = true ) { m_disableMouse = aDisabled; }
|
|
||||||
|
|
||||||
bool IsManuallyForced() const { return m_manuallyForced; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
SHAPE_LINE_CHAIN m_trail;
|
|
||||||
int m_tolerance;
|
|
||||||
DIRECTION_45 m_direction;
|
|
||||||
DIRECTION_45 m_lastSegDirection;
|
|
||||||
bool m_forced;
|
|
||||||
bool m_disableMouse;
|
|
||||||
bool m_manuallyForced;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Single track placement algorithm.
|
* Single track placement algorithm. Interactively routes a track.
|
||||||
*
|
* Applies shove and walkaround algorithms when needed.
|
||||||
* Interactively routes a track and applies shove and walk around algorithms when needed.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class LINE_PLACER : public PLACEMENT_ALGO
|
class LINE_PLACER : public PLACEMENT_ALGO
|
||||||
|
@ -225,6 +186,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Perform on-the-fly update of the width, via diameter & drill size from a settings class.
|
* Perform on-the-fly update of the width, via diameter & drill size from a settings class.
|
||||||
*
|
*
|
||||||
|
* Performs on-the-fly update of the width, via diameter & drill size from a settings class.
|
||||||
* Used to dynamically change these parameters as the track is routed.
|
* Used to dynamically change these parameters as the track is routed.
|
||||||
*/
|
*/
|
||||||
void UpdateSizes( const SIZES_SETTINGS& aSizes ) override;
|
void UpdateSizes( const SIZES_SETTINGS& aSizes ) override;
|
||||||
|
@ -336,7 +298,7 @@ private:
|
||||||
* colliding solid or non-movable items. Movable segments are ignored, as they'll be
|
* colliding solid or non-movable items. Movable segments are ignored, as they'll be
|
||||||
* handled later by the shove algorithm.
|
* handled later by the shove algorithm.
|
||||||
*/
|
*/
|
||||||
bool routeHead( const VECTOR2I& aP, LINE& aNewHead );
|
bool routeHead( const VECTOR2I& aP, LINE& aNewHead);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a single routing algorithm step, for the end point \a aP.
|
* Perform a single routing algorithm step, for the end point \a aP.
|
||||||
|
@ -347,10 +309,10 @@ private:
|
||||||
void routeStep( const VECTOR2I& aP );
|
void routeStep( const VECTOR2I& aP );
|
||||||
|
|
||||||
///< Route step walk around mode.
|
///< Route step walk around mode.
|
||||||
bool rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead );
|
bool rhWalkOnly( const VECTOR2I& aP, LINE& aNewHead);
|
||||||
|
|
||||||
///< Route step shove mode.
|
///< Route step shove mode.
|
||||||
bool rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead );
|
bool rhShoveOnly( const VECTOR2I& aP, LINE& aNewHead);
|
||||||
|
|
||||||
///< Route step mark obstacles mode.
|
///< Route step mark obstacles mode.
|
||||||
bool rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead );
|
bool rhMarkObstacles( const VECTOR2I& aP, LINE& aNewHead );
|
||||||
|
@ -398,7 +360,7 @@ private:
|
||||||
bool m_placementCorrect;
|
bool m_placementCorrect;
|
||||||
|
|
||||||
FIXED_TAIL m_fixedTail;
|
FIXED_TAIL m_fixedTail;
|
||||||
POSTURE_SOLVER m_postureSolver;
|
MOUSE_TRAIL_TRACER m_mouseTrailTracer;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,261 @@
|
||||||
|
/*
|
||||||
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013-2020 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.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pns_mouse_trail_tracer.h"
|
||||||
|
#include "pns_router.h"
|
||||||
|
#include "pns_debug_decorator.h"
|
||||||
|
|
||||||
|
namespace PNS {
|
||||||
|
|
||||||
|
MOUSE_TRAIL_TRACER::MOUSE_TRAIL_TRACER()
|
||||||
|
{
|
||||||
|
m_tolerance = 0;
|
||||||
|
m_disableMouse = false;
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MOUSE_TRAIL_TRACER::~MOUSE_TRAIL_TRACER() {}
|
||||||
|
|
||||||
|
|
||||||
|
void MOUSE_TRAIL_TRACER::Clear()
|
||||||
|
{
|
||||||
|
m_forced = false;
|
||||||
|
m_manuallyForced = false;
|
||||||
|
m_trail.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MOUSE_TRAIL_TRACER::AddTrailPoint( const VECTOR2I& aP )
|
||||||
|
{
|
||||||
|
if( m_trail.SegmentCount() == 0 )
|
||||||
|
{
|
||||||
|
m_trail.Append( aP );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SEG s_new( m_trail.CPoint( -1 ), aP );
|
||||||
|
|
||||||
|
for( int i = 0; i < m_trail.SegmentCount() - 1; i++ )
|
||||||
|
{
|
||||||
|
const SEG& s_trail = m_trail.CSegment( i );
|
||||||
|
|
||||||
|
if( s_trail.Distance( s_new ) <= m_tolerance )
|
||||||
|
{
|
||||||
|
m_trail = m_trail.Slice( 0, i );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_trail.Append( aP );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_trail.Simplify();
|
||||||
|
|
||||||
|
ROUTER::GetInstance()->GetInterface()->GetDebugDecorator()->AddLine( m_trail, 5, 100000 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DIRECTION_45 MOUSE_TRAIL_TRACER::GetPosture( const VECTOR2I& aP )
|
||||||
|
{
|
||||||
|
// Tuning factor for how good the "fit" of the trail must be to the posture
|
||||||
|
const double areaRatioThreshold = 1.3;
|
||||||
|
|
||||||
|
// Tuning factor to minimize flutter
|
||||||
|
const double areaRatioEpsilon = 0.25;
|
||||||
|
|
||||||
|
// Minimum distance factor of the trail before the min area test is used to lock the solver
|
||||||
|
const double minAreaCutoffDistanceFactor = 6;
|
||||||
|
|
||||||
|
// Adjusts how far away from p0 we get before whatever posture we solved is locked in
|
||||||
|
const int lockDistanceFactor = 25;
|
||||||
|
|
||||||
|
// Adjusts how close to p0 we unlock the posture again if one was locked already
|
||||||
|
const int unlockDistanceFactor = 4;
|
||||||
|
|
||||||
|
if( m_trail.PointCount() < 2 || m_manuallyForced )
|
||||||
|
{
|
||||||
|
// If mouse trail detection is enabled; using the last seg direction as a starting point
|
||||||
|
// will give the best results. Otherwise, just assume that we switch postures every
|
||||||
|
// segment.
|
||||||
|
if( !m_manuallyForced && m_lastSegDirection != DIRECTION_45::UNDEFINED )
|
||||||
|
m_direction = m_disableMouse ? m_lastSegDirection.Right() : m_lastSegDirection;
|
||||||
|
|
||||||
|
return m_direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_DECORATOR* dbg = ROUTER::GetInstance()->GetInterface()->GetDebugDecorator();
|
||||||
|
VECTOR2I p0 = m_trail.CPoint( 0 );
|
||||||
|
double refLength = SEG( p0, aP ).Length();
|
||||||
|
SHAPE_LINE_CHAIN straight( DIRECTION_45().BuildInitialTrace( p0, aP, false, false ) );
|
||||||
|
|
||||||
|
straight.SetClosed( true );
|
||||||
|
straight.Append( m_trail.Reverse() );
|
||||||
|
straight.Simplify();
|
||||||
|
dbg->AddLine( straight, m_forced ? 3 : 2, 100000 );
|
||||||
|
|
||||||
|
double areaS = std::abs( straight.Area() );
|
||||||
|
|
||||||
|
SHAPE_LINE_CHAIN diag( DIRECTION_45().BuildInitialTrace( p0, aP, true, false ) );
|
||||||
|
diag.Append( m_trail.Reverse() );
|
||||||
|
diag.SetClosed( true );
|
||||||
|
diag.Simplify();
|
||||||
|
dbg->AddLine( diag, 1, 100000 );
|
||||||
|
|
||||||
|
double areaDiag = std::abs( diag.Area() );
|
||||||
|
double ratio = areaS / ( areaDiag + 1.0 );
|
||||||
|
|
||||||
|
// heuristic to detect that the user dragged back the cursor to the beginning of the trace
|
||||||
|
// in this case, we cancel any forced posture and restart the trail
|
||||||
|
if( m_forced && refLength < unlockDistanceFactor * m_tolerance )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: Unlocked and reset" );
|
||||||
|
m_forced = false;
|
||||||
|
VECTOR2I start = p0;
|
||||||
|
m_trail.Clear();
|
||||||
|
m_trail.Append( start );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool areaOk = false;
|
||||||
|
|
||||||
|
// Check the actual trail area against the cutoff. This prevents flutter when the trail is
|
||||||
|
// very close to a straight line.
|
||||||
|
if( !m_forced && refLength > minAreaCutoffDistanceFactor * m_tolerance )
|
||||||
|
{
|
||||||
|
double areaCutoff = m_tolerance * refLength;
|
||||||
|
SHAPE_LINE_CHAIN trail( m_trail );
|
||||||
|
trail.SetClosed( true );
|
||||||
|
|
||||||
|
if( std::abs( trail.Area() ) > areaCutoff )
|
||||||
|
areaOk = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIRECTION_45 straightDirection;
|
||||||
|
DIRECTION_45 diagDirection;
|
||||||
|
DIRECTION_45 newDirection = m_direction;
|
||||||
|
|
||||||
|
straightDirection = DIRECTION_45( straight.CSegment( 0 ) );
|
||||||
|
diagDirection = DIRECTION_45( diag.CSegment( 0 ) );
|
||||||
|
|
||||||
|
if( !m_forced && areaOk && ratio > areaRatioThreshold + areaRatioEpsilon )
|
||||||
|
newDirection = diagDirection;
|
||||||
|
else if( !m_forced && areaOk && ratio < ( 1.0 / areaRatioThreshold ) - areaRatioEpsilon )
|
||||||
|
newDirection = straightDirection;
|
||||||
|
else
|
||||||
|
newDirection = m_direction.IsDiagonal() ? diagDirection : straightDirection;
|
||||||
|
|
||||||
|
if( !m_disableMouse && newDirection != m_direction )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: direction update %s => %s", m_direction.Format(),
|
||||||
|
newDirection.Format() );
|
||||||
|
m_direction = newDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a last segment, correct the direction relative to it. For segment exit, we want
|
||||||
|
// to correct to the least obtuse
|
||||||
|
if( !m_manuallyForced && !m_disableMouse && m_lastSegDirection != DIRECTION_45::UNDEFINED )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: checking direction %s against last seg %s",
|
||||||
|
m_direction.Format(), m_lastSegDirection.Format() );
|
||||||
|
|
||||||
|
if( straightDirection == m_lastSegDirection )
|
||||||
|
{
|
||||||
|
if( m_direction != straightDirection )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: forcing straight => %s", straightDirection.Format() );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_direction = straightDirection;
|
||||||
|
}
|
||||||
|
else if( diagDirection == m_lastSegDirection )
|
||||||
|
{
|
||||||
|
if( m_direction != straightDirection )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: forcing diagonal => %s", diagDirection.Format() );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_direction = diagDirection;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch( m_direction.Angle( m_lastSegDirection ) )
|
||||||
|
{
|
||||||
|
case DIRECTION_45::ANG_HALF_FULL:
|
||||||
|
// Force a better (acute) connection
|
||||||
|
m_direction = m_direction.IsDiagonal() ? straightDirection : diagDirection;
|
||||||
|
wxLogTrace( "PNS", "Posture: correcting half full => %s", m_direction.Format() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION_45::ANG_ACUTE:
|
||||||
|
{
|
||||||
|
// Force a better connection by flipping if possible
|
||||||
|
DIRECTION_45 candidate = m_direction.IsDiagonal() ? straightDirection
|
||||||
|
: diagDirection;
|
||||||
|
|
||||||
|
if( candidate.Angle( m_lastSegDirection ) == DIRECTION_45::ANG_RIGHT )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: correcting right => %s", candidate.Format() );
|
||||||
|
m_direction = candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DIRECTION_45::ANG_RIGHT:
|
||||||
|
{
|
||||||
|
// Force a better connection by flipping if possible
|
||||||
|
DIRECTION_45 candidate = m_direction.IsDiagonal() ? straightDirection
|
||||||
|
: diagDirection;
|
||||||
|
|
||||||
|
if( candidate.Angle( m_lastSegDirection ) == DIRECTION_45::ANG_OBTUSE )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: correcting obtuse => %s", candidate.Format() );
|
||||||
|
m_direction = candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we get far away from the initial point, lock in the current solution to prevent flutter
|
||||||
|
if( !m_forced && refLength > lockDistanceFactor * m_tolerance )
|
||||||
|
{
|
||||||
|
wxLogTrace( "PNS", "Posture: solution locked" );
|
||||||
|
m_forced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MOUSE_TRAIL_TRACER::FlipPosture()
|
||||||
|
{
|
||||||
|
m_direction = m_direction.Right();
|
||||||
|
m_forced = true;
|
||||||
|
m_manuallyForced = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013-2020 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.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PNS_MOUSE_TRAIL_TRACER_H
|
||||||
|
#define __PNS_MOUSE_TRAIL_TRACER_H
|
||||||
|
|
||||||
|
#include <math/vector2d.h>
|
||||||
|
|
||||||
|
#include <geometry/direction45.h>
|
||||||
|
#include <geometry/shape.h>
|
||||||
|
#include <geometry/shape_line_chain.h>
|
||||||
|
|
||||||
|
namespace PNS {
|
||||||
|
|
||||||
|
class MOUSE_TRAIL_TRACER
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MOUSE_TRAIL_TRACER();
|
||||||
|
~MOUSE_TRAIL_TRACER();
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
|
void AddTrailPoint( const VECTOR2I& aP );
|
||||||
|
|
||||||
|
void SetTolerance( int toll ) { m_tolerance = toll; }
|
||||||
|
|
||||||
|
void SetDefaultDirections( DIRECTION_45 aInitDirection, DIRECTION_45 aLastSegDir )
|
||||||
|
{
|
||||||
|
m_direction = aInitDirection;
|
||||||
|
m_lastSegDirection = aLastSegDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIRECTION_45 GetPosture( const VECTOR2I& aP );
|
||||||
|
|
||||||
|
void FlipPosture();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the mouse-trail portion of the posture solver; leaving only the manual posture
|
||||||
|
* switch and the previous-segment posture algorithm
|
||||||
|
*/
|
||||||
|
void SetMouseDisabled( bool aDisabled = true ) { m_disableMouse = aDisabled; }
|
||||||
|
|
||||||
|
bool IsManuallyForced() const { return m_manuallyForced; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SHAPE_LINE_CHAIN m_trail;
|
||||||
|
int m_tolerance;
|
||||||
|
DIRECTION_45 m_direction;
|
||||||
|
DIRECTION_45 m_lastSegDirection;
|
||||||
|
bool m_forced;
|
||||||
|
bool m_disableMouse;
|
||||||
|
bool m_manuallyForced;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PNS
|
||||||
|
|
||||||
|
#endif
|
|
@ -112,6 +112,6 @@ private:
|
||||||
std::map<int, int> m_layerPairs;
|
std::map<int, int> m_layerPairs;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
#endif // __PNS_SIZES_SETTINGS_H
|
#endif // __PNS_SIZES_SETTINGS_H
|
||||||
|
|
Loading…
Reference in New Issue