Converted tabs to spaces. Removed trailing whitespaces.
This commit is contained in:
parent
ac489ece7b
commit
22045b61ea
|
@ -78,21 +78,21 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||||
Connect( wxEVT_SIZE, wxSizeEventHandler( EDA_DRAW_PANEL_GAL::onSize ), NULL, this );
|
Connect( wxEVT_SIZE, wxSizeEventHandler( EDA_DRAW_PANEL_GAL::onSize ), NULL, this );
|
||||||
|
|
||||||
/* Generic events for the Tool Dispatcher */
|
/* Generic events for the Tool Dispatcher */
|
||||||
Connect( wxEVT_MOTION, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_MOTION, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_LEFT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_LEFT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_LEFT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_LEFT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_RIGHT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_RIGHT_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_RIGHT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_RIGHT_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_MIDDLE_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_MIDDLE_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_MIDDLE_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_MIDDLE_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) );
|
Connect( wxEVT_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) );
|
||||||
Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_ENTER_WINDOW, wxEventHandler( EDA_DRAW_PANEL_GAL::onEnter ), NULL, this );
|
Connect( wxEVT_ENTER_WINDOW, wxEventHandler( EDA_DRAW_PANEL_GAL::onEnter ), NULL, this );
|
||||||
Connect( KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE,
|
Connect( KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE,
|
||||||
wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
|
|
||||||
m_refreshTimer.SetOwner( this );
|
m_refreshTimer.SetOwner( this );
|
||||||
Connect( wxEVT_TIMER, wxTimerEventHandler( EDA_DRAW_PANEL_GAL::onRefreshTimer ), NULL, this );
|
Connect( wxEVT_TIMER, wxTimerEventHandler( EDA_DRAW_PANEL_GAL::onRefreshTimer ), NULL, this );
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect )
|
||||||
m_refreshTimer.Start( ( MinRefreshPeriod - delta ).ToLong(), true );
|
m_refreshTimer.Start( ( MinRefreshPeriod - delta ).ToLong(), true );
|
||||||
m_pendingRefresh = true;
|
m_pendingRefresh = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
|
void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
|
||||||
|
@ -223,13 +223,13 @@ void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
|
||||||
|
|
||||||
void EDA_DRAW_PANEL_GAL::onEvent( wxEvent& aEvent )
|
void EDA_DRAW_PANEL_GAL::onEvent( wxEvent& aEvent )
|
||||||
{
|
{
|
||||||
if( !m_eventDispatcher )
|
if( !m_eventDispatcher )
|
||||||
{
|
{
|
||||||
aEvent.Skip();
|
aEvent.Skip();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_eventDispatcher->DispatchWxEvent( aEvent );
|
m_eventDispatcher->DispatchWxEvent( aEvent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,6 @@ void COLOR4D::FromHSV( double aInH, double aInS, double aInV )
|
||||||
b = q;
|
b = q;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -168,7 +167,7 @@ COLOR4D& COLOR4D::Saturate( double aFactor )
|
||||||
double h, s, v;
|
double h, s, v;
|
||||||
ToHSV( h, s, v );
|
ToHSV( h, s, v );
|
||||||
FromHSV( h, aFactor, 1.0 );
|
FromHSV( h, aFactor, 1.0 );
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ void OPENGL_GAL::BeginDrawing()
|
||||||
glViewport( 0, 0, (GLsizei) screenSize.x, (GLsizei) screenSize.y );
|
glViewport( 0, 0, (GLsizei) screenSize.x, (GLsizei) screenSize.y );
|
||||||
|
|
||||||
// Create the screen transformation
|
// Create the screen transformation
|
||||||
glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y,
|
glOrtho( 0, (GLint) screenSize.x, 0, (GLsizei) screenSize.y,
|
||||||
-depthRange.x, -depthRange.y );
|
-depthRange.x, -depthRange.y );
|
||||||
|
|
||||||
// Prepare rendering target buffers
|
// Prepare rendering target buffers
|
||||||
|
|
|
@ -49,7 +49,7 @@ void strokedCircle( vec2 aCoord, float aRadius, float aWidth )
|
||||||
float innerRadius = aRadius - ( aWidth / 2 );
|
float innerRadius = aRadius - ( aWidth / 2 );
|
||||||
float relWidth = innerRadius / outerRadius;
|
float relWidth = innerRadius / outerRadius;
|
||||||
|
|
||||||
if( ( dot( aCoord, aCoord ) < 1.0f ) &&
|
if( ( dot( aCoord, aCoord ) < 1.0f ) &&
|
||||||
( dot( aCoord, aCoord ) > relWidth * relWidth ) )
|
( dot( aCoord, aCoord ) > relWidth * relWidth ) )
|
||||||
gl_FragColor = gl_Color;
|
gl_FragColor = gl_Color;
|
||||||
else
|
else
|
||||||
|
|
|
@ -42,23 +42,23 @@ void main()
|
||||||
{
|
{
|
||||||
// Pass attributes to the fragment shader
|
// Pass attributes to the fragment shader
|
||||||
shaderParams = attrShaderParams;
|
shaderParams = attrShaderParams;
|
||||||
|
|
||||||
if( shaderParams[0] == SHADER_LINE )
|
if( shaderParams[0] == SHADER_LINE )
|
||||||
{
|
{
|
||||||
float lineWidth = shaderParams[3];
|
float lineWidth = shaderParams[3];
|
||||||
float worldScale = gl_ModelViewMatrix[0][0];
|
float worldScale = gl_ModelViewMatrix[0][0];
|
||||||
float scale;
|
float scale;
|
||||||
|
|
||||||
// Make lines appear to be at least 1 pixel wide
|
// Make lines appear to be at least 1 pixel wide
|
||||||
if( worldScale * lineWidth < MIN_WIDTH )
|
if( worldScale * lineWidth < MIN_WIDTH )
|
||||||
scale = MIN_WIDTH / ( worldScale * lineWidth );
|
scale = MIN_WIDTH / ( worldScale * lineWidth );
|
||||||
else
|
else
|
||||||
scale = 1.0f;
|
scale = 1.0f;
|
||||||
|
|
||||||
gl_Position = gl_ModelViewProjectionMatrix *
|
gl_Position = gl_ModelViewProjectionMatrix *
|
||||||
( gl_Vertex + vec4( shaderParams.yz * scale, 0.0, 0.0 ) );
|
( gl_Vertex + vec4( shaderParams.yz * scale, 0.0, 0.0 ) );
|
||||||
}
|
}
|
||||||
else if( ( shaderParams[0] == SHADER_STROKED_CIRCLE ) ||
|
else if( ( shaderParams[0] == SHADER_STROKED_CIRCLE ) ||
|
||||||
( shaderParams[0] == SHADER_FILLED_CIRCLE ) )
|
( shaderParams[0] == SHADER_FILLED_CIRCLE ) )
|
||||||
{
|
{
|
||||||
// Compute relative circle coordinates basing on indices
|
// Compute relative circle coordinates basing on indices
|
||||||
|
@ -69,7 +69,7 @@ void main()
|
||||||
circleCoords = vec2( sqrt( 3.0f ), -1.0f );
|
circleCoords = vec2( sqrt( 3.0f ), -1.0f );
|
||||||
else if( shaderParams[1] == 3.0f )
|
else if( shaderParams[1] == 3.0f )
|
||||||
circleCoords = vec2( 0.0f, 2.0f );
|
circleCoords = vec2( 0.0f, 2.0f );
|
||||||
|
|
||||||
// Semicircle
|
// Semicircle
|
||||||
else if( shaderParams[1] == 4.0f )
|
else if( shaderParams[1] == 4.0f )
|
||||||
circleCoords = vec2( -3.0f / sqrt( 3.0f ), 0.0f );
|
circleCoords = vec2( -3.0f / sqrt( 3.0f ), 0.0f );
|
||||||
|
@ -81,7 +81,7 @@ void main()
|
||||||
// Make the line appear to be at least 1 pixel wide
|
// Make the line appear to be at least 1 pixel wide
|
||||||
float lineWidth = shaderParams[3];
|
float lineWidth = shaderParams[3];
|
||||||
float worldScale = gl_ModelViewMatrix[0][0];
|
float worldScale = gl_ModelViewMatrix[0][0];
|
||||||
|
|
||||||
// Make lines appear to be at least 1 pixel width
|
// Make lines appear to be at least 1 pixel width
|
||||||
if( worldScale * lineWidth < MIN_WIDTH )
|
if( worldScale * lineWidth < MIN_WIDTH )
|
||||||
shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth );
|
shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth );
|
||||||
|
@ -93,7 +93,7 @@ void main()
|
||||||
// Pass through the coordinates like in the fixed pipeline
|
// Pass through the coordinates like in the fixed pipeline
|
||||||
gl_Position = ftransform();
|
gl_Position = ftransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
gl_FrontColor = gl_Color;
|
gl_FrontColor = gl_Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,38 +32,38 @@ template<typename T> int sgn( T val ) {
|
||||||
|
|
||||||
bool SEG::PointCloserThan( const VECTOR2I& aP, int dist ) const
|
bool SEG::PointCloserThan( const VECTOR2I& aP, int dist ) const
|
||||||
{
|
{
|
||||||
VECTOR2I d = b - a;
|
VECTOR2I d = b - a;
|
||||||
ecoord dist_sq = (ecoord) dist * dist;
|
ecoord dist_sq = (ecoord) dist * dist;
|
||||||
|
|
||||||
SEG::ecoord l_squared = d.Dot( d );
|
SEG::ecoord l_squared = d.Dot( d );
|
||||||
SEG::ecoord t = d.Dot( aP - a );
|
SEG::ecoord t = d.Dot( aP - a );
|
||||||
|
|
||||||
if( t <= 0 || !l_squared )
|
if( t <= 0 || !l_squared )
|
||||||
return ( aP - a ).SquaredEuclideanNorm() < dist_sq;
|
return ( aP - a ).SquaredEuclideanNorm() < dist_sq;
|
||||||
else if( t >= l_squared )
|
else if( t >= l_squared )
|
||||||
return ( aP - b ).SquaredEuclideanNorm() < dist_sq;
|
return ( aP - b ).SquaredEuclideanNorm() < dist_sq;
|
||||||
|
|
||||||
int dxdy = abs( d.x ) - abs( d.y );
|
int dxdy = abs( d.x ) - abs( d.y );
|
||||||
|
|
||||||
if( ( dxdy >= -1 && dxdy <= 1 ) || abs( d.x ) <= 1 || abs( d.y ) <= 1 )
|
if( ( dxdy >= -1 && dxdy <= 1 ) || abs( d.x ) <= 1 || abs( d.y ) <= 1 )
|
||||||
{
|
{
|
||||||
int ca = -sgn( d.y );
|
int ca = -sgn( d.y );
|
||||||
int cb = sgn( d.x );
|
int cb = sgn( d.x );
|
||||||
int cc = -ca * a.x - cb * a.y;
|
int cc = -ca * a.x - cb * a.y;
|
||||||
|
|
||||||
ecoord num = ca * aP.x + cb * aP.y + cc;
|
|
||||||
num *= num;
|
|
||||||
|
|
||||||
if( ca && cb )
|
ecoord num = ca * aP.x + cb * aP.y + cc;
|
||||||
num >>= 1;
|
num *= num;
|
||||||
|
|
||||||
if( num > ( dist_sq + 100 ) )
|
if( ca && cb )
|
||||||
return false;
|
num >>= 1;
|
||||||
else if( num < ( dist_sq - 100 ) )
|
|
||||||
return true;
|
if( num > ( dist_sq + 100 ) )
|
||||||
|
return false;
|
||||||
|
else if( num < ( dist_sq - 100 ) )
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR2I nearest;
|
VECTOR2I nearest;
|
||||||
nearest.x = a.x + rescale( t, (ecoord)d.x, l_squared );
|
nearest.x = a.x + rescale( t, (ecoord)d.x, l_squared );
|
||||||
nearest.y = a.y + rescale( t, (ecoord)d.y, l_squared );
|
nearest.y = a.y + rescale( t, (ecoord)d.y, l_squared );
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ bool SEG::PointCloserThan( const VECTOR2I& aP, int dist ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
|
SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
|
||||||
{
|
{
|
||||||
// fixme: rather inefficient....
|
// fixme: rather inefficient....
|
||||||
if( Intersect( aSeg ) )
|
if( Intersect( aSeg ) )
|
||||||
|
@ -91,62 +91,62 @@ SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines ) const
|
OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines ) const
|
||||||
{
|
{
|
||||||
const VECTOR2I e ( b - a );
|
const VECTOR2I e ( b - a );
|
||||||
const VECTOR2I f ( aSeg.b - aSeg.a );
|
const VECTOR2I f ( aSeg.b - aSeg.a );
|
||||||
const VECTOR2I ac ( aSeg.a - a );
|
const VECTOR2I ac ( aSeg.a - a );
|
||||||
|
|
||||||
ecoord d = f.Cross( e );
|
|
||||||
ecoord p = f.Cross( ac );
|
|
||||||
ecoord q = e.Cross( ac );
|
|
||||||
|
|
||||||
if( d == 0 )
|
|
||||||
return OPT_VECTOR2I();
|
|
||||||
if ( !aLines && d > 0 && ( q < 0 || q > d || p < 0 || p > d ) )
|
|
||||||
return OPT_VECTOR2I();
|
|
||||||
if ( !aLines && d < 0 && ( q < d || p < d || p > 0 || q > 0 ) )
|
|
||||||
return OPT_VECTOR2I();
|
|
||||||
if ( !aLines && aIgnoreEndpoints && ( q == 0 || q == d ) && ( p == 0 || p == d ) )
|
|
||||||
return OPT_VECTOR2I();
|
|
||||||
|
|
||||||
VECTOR2I ip( aSeg.a.x + rescale( q, (ecoord)f.x, d ),
|
|
||||||
aSeg.a.y + rescale( q, (ecoord)f.y, d ) );
|
|
||||||
|
|
||||||
return ip;
|
ecoord d = f.Cross( e );
|
||||||
|
ecoord p = f.Cross( ac );
|
||||||
|
ecoord q = e.Cross( ac );
|
||||||
|
|
||||||
|
if( d == 0 )
|
||||||
|
return OPT_VECTOR2I();
|
||||||
|
if ( !aLines && d > 0 && ( q < 0 || q > d || p < 0 || p > d ) )
|
||||||
|
return OPT_VECTOR2I();
|
||||||
|
if ( !aLines && d < 0 && ( q < d || p < d || p > 0 || q > 0 ) )
|
||||||
|
return OPT_VECTOR2I();
|
||||||
|
if ( !aLines && aIgnoreEndpoints && ( q == 0 || q == d ) && ( p == 0 || p == d ) )
|
||||||
|
return OPT_VECTOR2I();
|
||||||
|
|
||||||
|
VECTOR2I ip( aSeg.a.x + rescale( q, (ecoord)f.x, d ),
|
||||||
|
aSeg.a.y + rescale( q, (ecoord)f.y, d ) );
|
||||||
|
|
||||||
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SEG::ccw( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c ) const
|
bool SEG::ccw( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c ) const
|
||||||
{
|
{
|
||||||
return (ecoord)( c.y - a.y ) * ( b.x - a.x ) > (ecoord)( b.y - a.y ) * ( c.x - a.x );
|
return (ecoord)( c.y - a.y ) * ( b.x - a.x ) > (ecoord)( b.y - a.y ) * ( c.x - a.x );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SEG::Collide( const SEG& aSeg, int aClearance ) const
|
bool SEG::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
{
|
{
|
||||||
// check for intersection
|
// check for intersection
|
||||||
// fixme: move to a method
|
// fixme: move to a method
|
||||||
if( ccw( a, aSeg.a, aSeg.b ) != ccw( b, aSeg.a, aSeg.b ) &&
|
if( ccw( a, aSeg.a, aSeg.b ) != ccw( b, aSeg.a, aSeg.b ) &&
|
||||||
ccw( a, b, aSeg.a ) != ccw( a, b, aSeg.b ) )
|
ccw( a, b, aSeg.a ) != ccw( a, b, aSeg.b ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
#define CHK(_seg, _pt) \
|
#define CHK(_seg, _pt) \
|
||||||
if( (_seg).PointCloserThan (_pt, aClearance ) ) return true;
|
if( (_seg).PointCloserThan (_pt, aClearance ) ) return true;
|
||||||
|
|
||||||
CHK( *this, aSeg.a );
|
CHK( *this, aSeg.a );
|
||||||
CHK( *this, aSeg.b );
|
CHK( *this, aSeg.b );
|
||||||
CHK( aSeg, a );
|
CHK( aSeg, a );
|
||||||
CHK( aSeg, b );
|
CHK( aSeg, b );
|
||||||
#undef CHK
|
#undef CHK
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SEG::Contains( const VECTOR2I& aP ) const
|
bool SEG::Contains( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
return PointCloserThan( aP, 1 );
|
return PointCloserThan( aP, 1 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,200 +34,200 @@ typedef VECTOR2I::extended_type ecoord;
|
||||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
bool aNeedMTV, VECTOR2I& aMTV )
|
||||||
{
|
{
|
||||||
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
|
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
|
||||||
ecoord min_dist_sq = min_dist * min_dist;
|
ecoord min_dist_sq = min_dist * min_dist;
|
||||||
|
|
||||||
const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
|
|
||||||
|
|
||||||
ecoord dist_sq = delta.SquaredEuclideanNorm();
|
const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
|
||||||
|
|
||||||
if ( dist_sq >= min_dist_sq )
|
ecoord dist_sq = delta.SquaredEuclideanNorm();
|
||||||
return false;
|
|
||||||
|
|
||||||
if ( aNeedMTV )
|
|
||||||
aMTV = delta.Resize( sqrt ( abs( min_dist_sq - dist_sq ) ) + 1 );
|
|
||||||
|
|
||||||
return true;
|
if ( dist_sq >= min_dist_sq )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( aNeedMTV )
|
||||||
|
aMTV = delta.Resize( sqrt ( abs( min_dist_sq - dist_sq ) ) + 1 );
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CIRCLE& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
bool aNeedMTV, VECTOR2I& aMTV )
|
||||||
{
|
{
|
||||||
const VECTOR2I c = aB.GetCenter();
|
const VECTOR2I c = aB.GetCenter();
|
||||||
const VECTOR2I p0 = aA.GetPosition();
|
const VECTOR2I p0 = aA.GetPosition();
|
||||||
const VECTOR2I size = aA.GetSize();
|
const VECTOR2I size = aA.GetSize();
|
||||||
const ecoord r = aB.GetRadius();
|
const ecoord r = aB.GetRadius();
|
||||||
const ecoord min_dist = aClearance + r;
|
const ecoord min_dist = aClearance + r;
|
||||||
const ecoord min_dist_sq = min_dist * min_dist;
|
const ecoord min_dist_sq = min_dist * min_dist;
|
||||||
|
|
||||||
if ( aA.BBox( 0 ).Contains( c ) )
|
if ( aA.BBox( 0 ).Contains( c ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
const VECTOR2I vts[] = {
|
|
||||||
VECTOR2I(p0.x, p0.y),
|
|
||||||
VECTOR2I(p0.x, p0.y + size.y),
|
|
||||||
VECTOR2I(p0.x + size.x, p0.y + size.y),
|
|
||||||
VECTOR2I(p0.x + size.x, p0.y),
|
|
||||||
VECTOR2I(p0.x, p0.y) };
|
|
||||||
|
|
||||||
ecoord nearest_seg_dist_sq = VECTOR2I::ECOORD_MAX;
|
const VECTOR2I vts[] = {
|
||||||
VECTOR2I nearest;
|
VECTOR2I(p0.x, p0.y),
|
||||||
|
VECTOR2I(p0.x, p0.y + size.y),
|
||||||
|
VECTOR2I(p0.x + size.x, p0.y + size.y),
|
||||||
|
VECTOR2I(p0.x + size.x, p0.y),
|
||||||
|
VECTOR2I(p0.x, p0.y) };
|
||||||
|
|
||||||
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
|
ecoord nearest_seg_dist_sq = VECTOR2I::ECOORD_MAX;
|
||||||
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
|
VECTOR2I nearest;
|
||||||
|
|
||||||
if( !inside )
|
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
|
||||||
{
|
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
|
||||||
|
|
||||||
for( int i = 0; i < 4; i++ )
|
if( !inside )
|
||||||
{
|
{
|
||||||
const SEG seg( vts[i], vts[i+1] );
|
|
||||||
ecoord dist_sq = seg.SquaredDistance( c );
|
|
||||||
|
|
||||||
if( dist_sq < min_dist_sq )
|
|
||||||
{
|
|
||||||
if( !aNeedMTV )
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nearest = seg.NearestPoint( c );
|
|
||||||
nearest_seg_dist_sq = dist_sq;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( nearest_seg_dist_sq >= min_dist_sq && !inside )
|
for( int i = 0; i < 4; i++ )
|
||||||
return false;
|
{
|
||||||
|
const SEG seg( vts[i], vts[i+1] );
|
||||||
|
ecoord dist_sq = seg.SquaredDistance( c );
|
||||||
|
|
||||||
VECTOR2I delta = c - nearest;
|
if( dist_sq < min_dist_sq )
|
||||||
|
{
|
||||||
|
if( !aNeedMTV )
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nearest = seg.NearestPoint( c );
|
||||||
|
nearest_seg_dist_sq = dist_sq;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( !aNeedMTV )
|
if( nearest_seg_dist_sq >= min_dist_sq && !inside )
|
||||||
return true;
|
return false;
|
||||||
|
|
||||||
if( inside )
|
VECTOR2I delta = c - nearest;
|
||||||
aMTV = -delta.Resize( sqrt( abs( r * r + nearest_seg_dist_sq ) + 1 ) );
|
|
||||||
else
|
|
||||||
aMTV = delta.Resize( sqrt( abs( r * r - nearest_seg_dist_sq ) + 1 ) );
|
|
||||||
|
|
||||||
return true;
|
if( !aNeedMTV )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( inside )
|
||||||
|
aMTV = -delta.Resize( sqrt( abs( r * r + nearest_seg_dist_sq ) + 1 ) );
|
||||||
|
else
|
||||||
|
aMTV = delta.Resize( sqrt( abs( r * r - nearest_seg_dist_sq ) + 1 ) );
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
bool aNeedMTV, VECTOR2I& aMTV )
|
||||||
{
|
{
|
||||||
for( int s = 0; s < aB.SegmentCount(); s++ )
|
for( int s = 0; s < aB.SegmentCount(); s++ )
|
||||||
{
|
{
|
||||||
if ( aA.Collide( aB.CSegment( s ), aClearance ) )
|
if ( aA.Collide( aB.CSegment( s ), aClearance ) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
bool aNeedMTV, VECTOR2I& aMTV )
|
||||||
{
|
{
|
||||||
for( int i = 0; i < aB.SegmentCount(); i++ )
|
for( int i = 0; i < aB.SegmentCount(); i++ )
|
||||||
if( aA.Collide( aB.CSegment(i), aClearance ) )
|
if( aA.Collide( aB.CSegment(i), aClearance ) )
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
|
||||||
bool aNeedMTV, VECTOR2I& aMTV )
|
bool aNeedMTV, VECTOR2I& aMTV )
|
||||||
{
|
{
|
||||||
for( int s = 0; s < aB.SegmentCount(); s++ )
|
for( int s = 0; s < aB.SegmentCount(); s++ )
|
||||||
{
|
{
|
||||||
SEG seg = aB.CSegment( s );
|
SEG seg = aB.CSegment( s );
|
||||||
if( aA.Collide( seg, aClearance ) )
|
if( aA.Collide( seg, aClearance ) )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
|
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
|
||||||
{
|
{
|
||||||
switch( aA->Type() )
|
switch( aA->Type() )
|
||||||
{
|
{
|
||||||
case SH_RECT:
|
case SH_RECT:
|
||||||
switch( aB->Type() )
|
switch( aB->Type() )
|
||||||
{
|
{
|
||||||
case SH_CIRCLE:
|
case SH_CIRCLE:
|
||||||
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
|
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
|
||||||
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
case SH_LINE_CHAIN:
|
||||||
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
|
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
|
||||||
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SH_CIRCLE:
|
case SH_CIRCLE:
|
||||||
switch( aB->Type() )
|
switch( aB->Type() )
|
||||||
{
|
{
|
||||||
case SH_RECT:
|
case SH_RECT:
|
||||||
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
|
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
|
||||||
*static_cast<const SHAPE_CIRCLE*>( aA ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_CIRCLE*>( aA ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
case SH_CIRCLE:
|
case SH_CIRCLE:
|
||||||
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
|
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
|
||||||
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
case SH_LINE_CHAIN:
|
||||||
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
|
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
|
||||||
*static_cast<const SHAPE_LINE_CHAIN *>( aB ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_LINE_CHAIN *>( aB ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
case SH_LINE_CHAIN:
|
||||||
switch( aB->Type() )
|
switch( aB->Type() )
|
||||||
{
|
{
|
||||||
case SH_RECT:
|
case SH_RECT:
|
||||||
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
|
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
|
||||||
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
case SH_CIRCLE:
|
case SH_CIRCLE:
|
||||||
return Collide( *static_cast<const SHAPE_CIRCLE*>( aB ),
|
return Collide( *static_cast<const SHAPE_CIRCLE*>( aB ),
|
||||||
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
case SH_LINE_CHAIN:
|
case SH_LINE_CHAIN:
|
||||||
return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( aA ),
|
return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( aA ),
|
||||||
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
|
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool unsupported_collision = true;
|
bool unsupported_collision = true;
|
||||||
|
|
||||||
assert( unsupported_collision == false );
|
assert( unsupported_collision == false );
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE::Collide( const SHAPE* aShape, int aClerance, VECTOR2I& aMTV ) const
|
bool SHAPE::Collide( const SHAPE* aShape, int aClerance, VECTOR2I& aMTV ) const
|
||||||
{
|
{
|
||||||
return CollideShapes( this, aShape, aClerance, true, aMTV);
|
return CollideShapes( this, aShape, aClerance, true, aMTV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE::Collide ( const SHAPE* aShape, int aClerance ) const
|
bool SHAPE::Collide ( const SHAPE* aShape, int aClerance ) const
|
||||||
{
|
{
|
||||||
VECTOR2I dummy;
|
VECTOR2I dummy;
|
||||||
return CollideShapes( this, aShape, aClerance, false, dummy );
|
return CollideShapes( this, aShape, aClerance, false, dummy );
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,491 +30,491 @@ using boost::optional;
|
||||||
|
|
||||||
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const
|
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const
|
||||||
{
|
{
|
||||||
assert( false );
|
assert( false );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_LINE_CHAIN::Collide( const BOX2I& aBox, int aClearance ) const
|
bool SHAPE_LINE_CHAIN::Collide( const BOX2I& aBox, int aClearance ) const
|
||||||
{
|
{
|
||||||
assert( false );
|
assert( false );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const
|
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const
|
||||||
{
|
{
|
||||||
BOX2I box_a( aSeg.a, aSeg.b - aSeg.a );
|
BOX2I box_a( aSeg.a, aSeg.b - aSeg.a );
|
||||||
BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
|
BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
|
||||||
|
|
||||||
for( int i = 0; i < SegmentCount() ;i++ )
|
for( int i = 0; i < SegmentCount() ;i++ )
|
||||||
{
|
{
|
||||||
const SEG& s = CSegment( i );
|
const SEG& s = CSegment( i );
|
||||||
BOX2I box_b( s.a, s.b - s.a );
|
BOX2I box_b( s.a, s.b - s.a );
|
||||||
|
|
||||||
BOX2I::ecoord_type d = box_a.SquaredDistance ( box_b );
|
|
||||||
|
|
||||||
if( d < dist_sq )
|
BOX2I::ecoord_type d = box_a.SquaredDistance ( box_b );
|
||||||
{
|
|
||||||
if( s.Collide( aSeg, aClearance ) )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
if( d < dist_sq )
|
||||||
|
{
|
||||||
|
if( s.Collide( aSeg, aClearance ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const
|
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Reverse() const
|
||||||
{
|
{
|
||||||
SHAPE_LINE_CHAIN a( *this );
|
SHAPE_LINE_CHAIN a( *this );
|
||||||
reverse( a.m_points.begin(), a.m_points.end() );
|
reverse( a.m_points.begin(), a.m_points.end() );
|
||||||
a.m_closed = m_closed;
|
a.m_closed = m_closed;
|
||||||
|
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::Length() const
|
int SHAPE_LINE_CHAIN::Length() const
|
||||||
{
|
{
|
||||||
int l = 0;
|
int l = 0;
|
||||||
for( int i = 0; i < SegmentCount(); i++ )
|
for( int i = 0; i < SegmentCount(); i++ )
|
||||||
l += CSegment( i ).Length();
|
l += CSegment( i ).Length();
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP )
|
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP )
|
||||||
{
|
{
|
||||||
if( aEndIndex < 0 )
|
if( aEndIndex < 0 )
|
||||||
aEndIndex += PointCount();
|
aEndIndex += PointCount();
|
||||||
if( aStartIndex < 0 )
|
if( aStartIndex < 0 )
|
||||||
aStartIndex += PointCount();
|
aStartIndex += PointCount();
|
||||||
|
|
||||||
if( aStartIndex == aEndIndex )
|
if( aStartIndex == aEndIndex )
|
||||||
m_points [aStartIndex] = aP;
|
m_points [aStartIndex] = aP;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 );
|
m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 );
|
||||||
m_points[aStartIndex] = aP;
|
m_points[aStartIndex] = aP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine )
|
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine )
|
||||||
{
|
{
|
||||||
if( aEndIndex < 0 )
|
if( aEndIndex < 0 )
|
||||||
aEndIndex += PointCount();
|
aEndIndex += PointCount();
|
||||||
if( aStartIndex < 0 )
|
if( aStartIndex < 0 )
|
||||||
aStartIndex += PointCount();
|
aStartIndex += PointCount();
|
||||||
|
|
||||||
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
|
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
|
||||||
m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() );
|
m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
|
void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
|
||||||
{
|
{
|
||||||
if(aEndIndex < 0)
|
if(aEndIndex < 0)
|
||||||
aEndIndex += PointCount();
|
aEndIndex += PointCount();
|
||||||
if(aStartIndex < 0)
|
if(aStartIndex < 0)
|
||||||
aStartIndex += PointCount();
|
aStartIndex += PointCount();
|
||||||
|
|
||||||
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
|
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP ) const
|
int SHAPE_LINE_CHAIN::Distance( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
int d = INT_MAX;
|
int d = INT_MAX;
|
||||||
for( int s = 0; s < SegmentCount(); s++ )
|
for( int s = 0; s < SegmentCount(); s++ )
|
||||||
d = min( d, CSegment( s ).Distance( aP ) );
|
d = min( d, CSegment( s ).Distance( aP ) );
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP )
|
int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP )
|
||||||
{
|
{
|
||||||
int ii = -1;
|
int ii = -1;
|
||||||
int min_dist = 2;
|
int min_dist = 2;
|
||||||
|
|
||||||
ii = Find( aP );
|
ii = Find( aP );
|
||||||
|
|
||||||
if( ii >= 0 )
|
if( ii >= 0 )
|
||||||
return ii;
|
return ii;
|
||||||
|
|
||||||
for( int s = 0; s < SegmentCount(); s++ )
|
for( int s = 0; s < SegmentCount(); s++ )
|
||||||
{
|
{
|
||||||
const SEG seg = CSegment( s );
|
const SEG seg = CSegment( s );
|
||||||
int dist = seg.Distance( aP );
|
int dist = seg.Distance( aP );
|
||||||
|
|
||||||
// make sure we are not producing a 'slightly concave' primitive. This might happen
|
// make sure we are not producing a 'slightly concave' primitive. This might happen
|
||||||
// if aP lies very close to one of already existing points.
|
// if aP lies very close to one of already existing points.
|
||||||
if( dist < min_dist && seg.a != aP && seg.b != aP )
|
if( dist < min_dist && seg.a != aP && seg.b != aP )
|
||||||
{
|
{
|
||||||
min_dist = dist;
|
min_dist = dist;
|
||||||
ii = s;
|
ii = s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( ii >= 0 )
|
if( ii >= 0 )
|
||||||
{
|
{
|
||||||
m_points.insert( m_points.begin() + ii + 1, aP );
|
m_points.insert( m_points.begin() + ii + 1, aP );
|
||||||
|
|
||||||
return ii + 1;
|
return ii + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const
|
int SHAPE_LINE_CHAIN::Find( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
for( int s = 0; s< PointCount(); s++ )
|
for( int s = 0; s< PointCount(); s++ )
|
||||||
if( CPoint( s ) == aP )
|
if( CPoint( s ) == aP )
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const
|
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const
|
||||||
{
|
{
|
||||||
SHAPE_LINE_CHAIN rv;
|
SHAPE_LINE_CHAIN rv;
|
||||||
|
|
||||||
if( aEndIndex < 0 )
|
|
||||||
aEndIndex += PointCount();
|
|
||||||
if( aStartIndex < 0 )
|
|
||||||
aStartIndex += PointCount();
|
|
||||||
|
|
||||||
for( int i = aStartIndex; i <= aEndIndex; i++ )
|
if( aEndIndex < 0 )
|
||||||
rv.Append( m_points[i] );
|
aEndIndex += PointCount();
|
||||||
|
if( aStartIndex < 0 )
|
||||||
|
aStartIndex += PointCount();
|
||||||
|
|
||||||
return rv;
|
for( int i = aStartIndex; i <= aEndIndex; i++ )
|
||||||
|
rv.Append( m_points[i] );
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct compareOriginDistance
|
struct compareOriginDistance
|
||||||
{
|
{
|
||||||
compareOriginDistance( VECTOR2I& aOrigin ):
|
compareOriginDistance( VECTOR2I& aOrigin ):
|
||||||
m_origin( aOrigin ) {};
|
m_origin( aOrigin ) {};
|
||||||
|
|
||||||
bool operator()( const SHAPE_LINE_CHAIN::Intersection& aA,
|
bool operator()( const SHAPE_LINE_CHAIN::Intersection& aA,
|
||||||
const SHAPE_LINE_CHAIN::Intersection& aB )
|
const SHAPE_LINE_CHAIN::Intersection& aB )
|
||||||
{
|
{
|
||||||
return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
|
return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
|
||||||
}
|
}
|
||||||
|
|
||||||
VECTOR2I m_origin;
|
VECTOR2I m_origin;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::Intersect( const SEG& aSeg, Intersections& aIp ) const
|
int SHAPE_LINE_CHAIN::Intersect( const SEG& aSeg, Intersections& aIp ) const
|
||||||
{
|
{
|
||||||
for( int s = 0; s < SegmentCount(); s++ )
|
for( int s = 0; s < SegmentCount(); s++ )
|
||||||
{
|
{
|
||||||
OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg );
|
OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg );
|
||||||
if( p )
|
if( p )
|
||||||
{
|
{
|
||||||
Intersection is;
|
Intersection is;
|
||||||
is.our = CSegment( s );
|
is.our = CSegment( s );
|
||||||
is.their = aSeg;
|
is.their = aSeg;
|
||||||
is.p = *p;
|
is.p = *p;
|
||||||
aIp.push_back( is );
|
aIp.push_back( is );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compareOriginDistance comp( aSeg.a );
|
compareOriginDistance comp( aSeg.a );
|
||||||
sort( aIp.begin(), aIp.end(), comp );
|
sort( aIp.begin(), aIp.end(), comp );
|
||||||
|
|
||||||
return aIp.size();
|
return aIp.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, Intersections& aIp ) const
|
int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, Intersections& aIp ) const
|
||||||
{
|
{
|
||||||
BOX2I bb_other = aChain.BBox();
|
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 ) )
|
for ( int s1 = 0; s1 < SegmentCount(); s1++ )
|
||||||
continue;
|
{
|
||||||
|
const SEG& a = CSegment( s1 );
|
||||||
|
const BOX2I bb_cur( a.a, a.b - a.a );
|
||||||
|
|
||||||
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
|
if( !bb_other.Intersects( bb_cur ) )
|
||||||
{
|
continue;
|
||||||
const SEG& b = aChain.CSegment( s2 );
|
|
||||||
Intersection is;
|
|
||||||
|
|
||||||
if( a.Collinear( 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();
|
|
||||||
|
|
||||||
for( int s1 = 0; s1 < SegmentCount(); s1++ )
|
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
|
||||||
{
|
{
|
||||||
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
|
const SEG& b = aChain.CSegment( s2 );
|
||||||
{
|
Intersection is;
|
||||||
const SEG& a = CSegment( s1 );
|
|
||||||
const SEG& b = aChain.CSegment( s2 );
|
|
||||||
OPT_VECTOR2I p = a.Intersect( b );
|
|
||||||
Intersection is;
|
|
||||||
|
|
||||||
if( p )
|
|
||||||
{
|
|
||||||
is.p = *p;
|
|
||||||
is.our = a;
|
|
||||||
is.their = b;
|
|
||||||
aIp.push_back( is );
|
|
||||||
}
|
|
||||||
else if( a.Collinear( b ) )
|
|
||||||
{
|
|
||||||
if( a.a != b.a && a.a != b.b && b.Contains( a.a ) )
|
|
||||||
{
|
|
||||||
is.p = a.a;
|
|
||||||
is.our = a;
|
|
||||||
is.their = b;
|
|
||||||
aIp.push_back( is );
|
|
||||||
}
|
|
||||||
else if( a.b != b.a && a.b != b.b && b.Contains( a.b ) )
|
|
||||||
{
|
|
||||||
is.p = a.b;
|
|
||||||
is.our = a;
|
|
||||||
is.their = b;
|
|
||||||
aIp.push_back( is );
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
if( a.Collinear( 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 );
|
||||||
|
|
||||||
return aIp.size();
|
if( p )
|
||||||
|
{
|
||||||
|
is.p = *p;
|
||||||
|
is.our = a;
|
||||||
|
is.their = b;
|
||||||
|
aIp.push_back( is );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aIp.size();
|
||||||
|
|
||||||
|
for( int s1 = 0; s1 < SegmentCount(); s1++ )
|
||||||
|
{
|
||||||
|
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
|
||||||
|
{
|
||||||
|
const SEG& a = CSegment( s1 );
|
||||||
|
const SEG& b = aChain.CSegment( s2 );
|
||||||
|
OPT_VECTOR2I p = a.Intersect( b );
|
||||||
|
Intersection is;
|
||||||
|
|
||||||
|
if( p )
|
||||||
|
{
|
||||||
|
is.p = *p;
|
||||||
|
is.our = a;
|
||||||
|
is.their = b;
|
||||||
|
aIp.push_back( is );
|
||||||
|
}
|
||||||
|
else if( a.Collinear( b ) )
|
||||||
|
{
|
||||||
|
if( a.a != b.a && a.a != b.b && b.Contains( a.a ) )
|
||||||
|
{
|
||||||
|
is.p = a.a;
|
||||||
|
is.our = a;
|
||||||
|
is.their = b;
|
||||||
|
aIp.push_back( is );
|
||||||
|
}
|
||||||
|
else if( a.b != b.a && a.b != b.b && b.Contains( a.b ) )
|
||||||
|
{
|
||||||
|
is.p = a.b;
|
||||||
|
is.our = a;
|
||||||
|
is.their = b;
|
||||||
|
aIp.push_back( is );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aIp.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int SHAPE_LINE_CHAIN::PathLength( const VECTOR2I& aP ) const
|
int SHAPE_LINE_CHAIN::PathLength( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
for( int i = 0; i < SegmentCount(); i++ )
|
for( int i = 0; i < SegmentCount(); i++ )
|
||||||
{
|
{
|
||||||
const SEG seg = CSegment( i );
|
const SEG seg = CSegment( i );
|
||||||
int d = seg.Distance( aP );
|
int d = seg.Distance( aP );
|
||||||
|
|
||||||
if( d <= 1 )
|
if( d <= 1 )
|
||||||
{
|
{
|
||||||
sum += ( aP - seg.a ).EuclideanNorm();
|
sum += ( aP - seg.a ).EuclideanNorm();
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
sum += seg.Length();
|
sum += seg.Length();
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP ) const
|
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
if( !m_closed || SegmentCount() < 3 )
|
if( !m_closed || SegmentCount() < 3 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int cur = CSegment(0).Side( aP );
|
int cur = CSegment(0).Side( aP );
|
||||||
|
|
||||||
if( cur == 0 )
|
if( cur == 0 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for( int i = 1; i < SegmentCount(); i++ )
|
for( int i = 1; i < SegmentCount(); i++ )
|
||||||
{
|
{
|
||||||
const SEG s = CSegment( i );
|
const SEG s = CSegment( i );
|
||||||
|
|
||||||
if( aP == s.a || aP == s.b ) // edge does not belong to the interior!
|
if( aP == s.a || aP == s.b ) // edge does not belong to the interior!
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( s.Side(aP) != cur )
|
if( s.Side(aP) != cur )
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP ) const
|
bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
if( SegmentCount() < 1 )
|
if( SegmentCount() < 1 )
|
||||||
return m_points[0] == aP;
|
return m_points[0] == aP;
|
||||||
|
|
||||||
for( int i = 1; i < SegmentCount(); i++ )
|
for( int i = 1; i < SegmentCount(); i++ )
|
||||||
{
|
{
|
||||||
const SEG s = CSegment( i );
|
const SEG s = CSegment( i );
|
||||||
|
|
||||||
if( s.a == aP || s.b == aP )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if( s.Distance(aP) <= 1 )
|
if( s.a == aP || s.b == aP )
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
if( s.Distance(aP) <= 1 )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const optional<SHAPE_LINE_CHAIN::Intersection> SHAPE_LINE_CHAIN::SelfIntersecting() const
|
const optional<SHAPE_LINE_CHAIN::Intersection> SHAPE_LINE_CHAIN::SelfIntersecting() const
|
||||||
{
|
{
|
||||||
for( int s1 = 0; s1 < SegmentCount(); s1++ )
|
for( int s1 = 0; s1 < SegmentCount(); s1++ )
|
||||||
{
|
{
|
||||||
for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ )
|
for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ )
|
||||||
{
|
{
|
||||||
const VECTOR2I s2a = CSegment( s2 ).a, s2b = CSegment( s2 ).b;
|
const VECTOR2I s2a = CSegment( s2 ).a, s2b = CSegment( s2 ).b;
|
||||||
if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) )
|
if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) )
|
||||||
{
|
{
|
||||||
Intersection is;
|
Intersection is;
|
||||||
is.our = CSegment( s1 );
|
is.our = CSegment( s1 );
|
||||||
is.their = CSegment( s2 );
|
is.their = CSegment( s2 );
|
||||||
is.p = s2a;
|
is.p = s2a;
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
else if( CSegment( s1 ).Contains(s2b ) )
|
else if( CSegment( s1 ).Contains(s2b ) )
|
||||||
{
|
{
|
||||||
Intersection is;
|
Intersection is;
|
||||||
is.our = CSegment( s1 );
|
is.our = CSegment( s1 );
|
||||||
is.their = CSegment( s2 );
|
is.their = CSegment( s2 );
|
||||||
is.p = s2b;
|
is.p = s2b;
|
||||||
return is;
|
return is;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OPT_VECTOR2I p = CSegment( s1 ).Intersect( CSegment( s2 ), true );
|
OPT_VECTOR2I p = CSegment( s1 ).Intersect( CSegment( s2 ), true );
|
||||||
|
|
||||||
if( p )
|
|
||||||
{
|
|
||||||
Intersection is;
|
|
||||||
is.our = CSegment( s1 );
|
|
||||||
is.their = CSegment( s2 );
|
|
||||||
is.p = *p;
|
|
||||||
return is;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return optional<Intersection>();
|
if( p )
|
||||||
|
{
|
||||||
|
Intersection is;
|
||||||
|
is.our = CSegment( s1 );
|
||||||
|
is.their = CSegment( s2 );
|
||||||
|
is.p = *p;
|
||||||
|
return is;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return optional<Intersection>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
|
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
|
||||||
{
|
{
|
||||||
vector<VECTOR2I> pts_unique;
|
vector<VECTOR2I> pts_unique;
|
||||||
|
|
||||||
if( PointCount() < 2 )
|
|
||||||
{
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
else if( PointCount() == 2 )
|
|
||||||
{
|
|
||||||
if( m_points[0] == m_points[1] )
|
|
||||||
m_points.erase( m_points.end() );
|
|
||||||
|
|
||||||
return *this;
|
if( PointCount() < 2 )
|
||||||
}
|
{
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
else if( PointCount() == 2 )
|
||||||
|
{
|
||||||
|
if( m_points[0] == m_points[1] )
|
||||||
|
m_points.erase( m_points.end() );
|
||||||
|
|
||||||
int i = 0;
|
return *this;
|
||||||
int np = PointCount();
|
}
|
||||||
|
|
||||||
// stage 1: eliminate duplicate vertices
|
|
||||||
while ( i < np )
|
|
||||||
{
|
|
||||||
int j = i + 1;
|
|
||||||
while( j < np && CPoint(i) == CPoint( j ) )
|
|
||||||
j++;
|
|
||||||
|
|
||||||
pts_unique.push_back( CPoint( i ) );
|
int i = 0;
|
||||||
i = j;
|
int np = PointCount();
|
||||||
}
|
|
||||||
|
|
||||||
m_points.clear();
|
// stage 1: eliminate duplicate vertices
|
||||||
np = pts_unique.size();
|
while ( i < np )
|
||||||
|
{
|
||||||
|
int j = i + 1;
|
||||||
|
while( j < np && CPoint(i) == CPoint( j ) )
|
||||||
|
j++;
|
||||||
|
|
||||||
i = 0;
|
pts_unique.push_back( CPoint( i ) );
|
||||||
// stage 1: eliminate collinear segments
|
i = j;
|
||||||
while( i < np - 2 )
|
}
|
||||||
{
|
|
||||||
const VECTOR2I p0 = pts_unique[i];
|
|
||||||
const VECTOR2I p1 = pts_unique[i+1];
|
|
||||||
int n = i;
|
|
||||||
|
|
||||||
while( n < np - 2 && SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 )
|
m_points.clear();
|
||||||
n++;
|
np = pts_unique.size();
|
||||||
|
|
||||||
m_points.push_back( p0 );
|
|
||||||
if( n > i )
|
|
||||||
i = n;
|
|
||||||
|
|
||||||
if( n == np )
|
i = 0;
|
||||||
{
|
// stage 1: eliminate collinear segments
|
||||||
m_points.push_back( pts_unique[n - 1] );
|
while( i < np - 2 )
|
||||||
return *this;
|
{
|
||||||
}
|
const VECTOR2I p0 = pts_unique[i];
|
||||||
|
const VECTOR2I p1 = pts_unique[i+1];
|
||||||
|
int n = i;
|
||||||
|
|
||||||
i++;
|
while( n < np - 2 && SEG( p0, p1 ).LineDistance( pts_unique[n + 2] ) <= 1 )
|
||||||
}
|
n++;
|
||||||
|
|
||||||
if( np > 1 )
|
m_points.push_back( p0 );
|
||||||
m_points.push_back( pts_unique[np - 2] );
|
if( n > i )
|
||||||
|
i = n;
|
||||||
|
|
||||||
m_points.push_back( pts_unique[np - 1] );
|
if( n == np )
|
||||||
|
{
|
||||||
|
m_points.push_back( pts_unique[n - 1] );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( np > 1 )
|
||||||
|
m_points.push_back( pts_unique[np - 2] );
|
||||||
|
|
||||||
|
m_points.push_back( pts_unique[np - 1] );
|
||||||
|
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const
|
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
int min_d = INT_MAX;
|
int min_d = INT_MAX;
|
||||||
int nearest = 0;
|
int nearest = 0;
|
||||||
for ( int i = 0; i < SegmentCount(); i++ )
|
for ( int i = 0; i < SegmentCount(); i++ )
|
||||||
{
|
{
|
||||||
int d = CSegment( i ).Distance( aP );
|
int d = CSegment( i ).Distance( aP );
|
||||||
if( d < min_d )
|
if( d < min_d )
|
||||||
{
|
{
|
||||||
min_d = d;
|
min_d = d;
|
||||||
nearest = i;
|
nearest = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CSegment( nearest ).NearestPoint( aP );
|
return CSegment( nearest ).NearestPoint( aP );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const string SHAPE_LINE_CHAIN::Format() const
|
const string SHAPE_LINE_CHAIN::Format() const
|
||||||
{
|
{
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
|
|
||||||
ss << m_points.size() << " " << ( m_closed ? 1 : 0 ) << " " ;
|
ss << m_points.size() << " " << ( m_closed ? 1 : 0 ) << " " ;
|
||||||
|
|
||||||
for( int i = 0; i < PointCount(); i++ )
|
for( int i = 0; i < PointCount(); i++ )
|
||||||
ss << m_points[i].x << " " << m_points[i].y << " ";// Format() << " ";
|
ss << m_points[i].x << " " << m_points[i].y << " ";// Format() << " ";
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
Boost::Context assembly wrapper - done to avoid compiling the whole boost binary library
|
Boost::Context assembly wrapper - done to avoid compiling the whole boost binary library
|
||||||
which may be unpleasant, in particular under Windows (we don't support VC++, while boost::context
|
which may be unpleasant, in particular under Windows (we don't support VC++, while boost::context
|
||||||
does not support mingw */
|
does not support mingw */
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
|
|
||||||
|
|
|
@ -9,39 +9,39 @@
|
||||||
.align 2
|
.align 2
|
||||||
|
|
||||||
_make_fcontext:
|
_make_fcontext:
|
||||||
mov 0x4(%esp),%eax
|
mov 0x4(%esp),%eax
|
||||||
lea -0x34(%eax),%eax
|
lea -0x34(%eax),%eax
|
||||||
and $0xfffffff0,%eax
|
and $0xfffffff0,%eax
|
||||||
mov 0x4(%esp),%ecx
|
mov 0x4(%esp),%ecx
|
||||||
mov %ecx,0x18(%eax)
|
mov %ecx,0x18(%eax)
|
||||||
mov 0x8(%esp),%edx
|
mov 0x8(%esp),%edx
|
||||||
mov %edx,0x1c(%eax)
|
mov %edx,0x1c(%eax)
|
||||||
neg %edx
|
neg %edx
|
||||||
lea (%edx,%ecx,1),%ecx
|
lea (%edx,%ecx,1),%ecx
|
||||||
mov %ecx,0x20(%eax)
|
mov %ecx,0x20(%eax)
|
||||||
mov 0xc(%esp),%ecx
|
mov 0xc(%esp),%ecx
|
||||||
mov %ecx,0x14(%eax)
|
mov %ecx,0x14(%eax)
|
||||||
stmxcsr 0x2c(%eax)
|
stmxcsr 0x2c(%eax)
|
||||||
fnstcw 0x30(%eax)
|
fnstcw 0x30(%eax)
|
||||||
lea -0x1c(%eax),%edx
|
lea -0x1c(%eax),%edx
|
||||||
mov %edx,0x10(%eax)
|
mov %edx,0x10(%eax)
|
||||||
mov $0x0,%ecx
|
mov $0x0,%ecx
|
||||||
mov %ecx,(%edx)
|
mov %ecx,(%edx)
|
||||||
mov %fs:0x18,%ecx
|
mov %fs:0x18,%ecx
|
||||||
mov (%ecx),%edx
|
mov (%ecx),%edx
|
||||||
inc %edx
|
inc %edx
|
||||||
je _make_fcontext+0x4c // <_make_fcontext+0x4c>
|
je _make_fcontext+0x4c // <_make_fcontext+0x4c>
|
||||||
dec %edx
|
dec %edx
|
||||||
xchg %edx,%ecx
|
xchg %edx,%ecx
|
||||||
jmp _make_fcontext+0x42 // <_make_fcontext+0x42>
|
jmp _make_fcontext+0x42 // <_make_fcontext+0x42>
|
||||||
mov 0x4(%ecx),%ecx
|
mov 0x4(%ecx),%ecx
|
||||||
mov 0x10(%eax),%edx
|
mov 0x10(%eax),%edx
|
||||||
mov %ecx,0x18(%edx)
|
mov %ecx,0x18(%edx)
|
||||||
mov $0xffffffff,%ecx
|
mov $0xffffffff,%ecx
|
||||||
mov %ecx,0x14(%edx)
|
mov %ecx,0x14(%edx)
|
||||||
lea 0x14(%edx),%ecx
|
lea 0x14(%edx),%ecx
|
||||||
mov %ecx,0x24(%eax)
|
mov %ecx,0x24(%eax)
|
||||||
ret
|
ret
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
xor %eax,%eax
|
xor %eax,%eax
|
||||||
|
|
|
@ -31,14 +31,14 @@
|
||||||
CONTEXT_MENU::CONTEXT_MENU() :
|
CONTEXT_MENU::CONTEXT_MENU() :
|
||||||
m_titleSet( false ), m_handler( this ), m_tool( NULL )
|
m_titleSet( false ), m_handler( this ), m_tool( NULL )
|
||||||
{
|
{
|
||||||
m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
|
m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
|
||||||
NULL, &m_handler );
|
NULL, &m_handler );
|
||||||
m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
|
m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
|
||||||
NULL, &m_handler );
|
NULL, &m_handler );
|
||||||
|
|
||||||
// Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
|
// Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
|
||||||
wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu );
|
wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu );
|
||||||
m_menu.AddPendingEvent( menuEvent );
|
m_menu.AddPendingEvent( menuEvent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,16 +72,16 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle )
|
||||||
// TODO handle an empty string (remove title and separator)
|
// TODO handle an empty string (remove title and separator)
|
||||||
|
|
||||||
// Unfortunately wxMenu::SetTitle() does nothing..
|
// Unfortunately wxMenu::SetTitle() does nothing..
|
||||||
if( m_titleSet )
|
if( m_titleSet )
|
||||||
{
|
{
|
||||||
m_menu.FindItemByPosition( 0 )->SetItemLabel( aTitle );
|
m_menu.FindItemByPosition( 0 )->SetItemLabel( aTitle );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_menu.InsertSeparator( 0 );
|
m_menu.InsertSeparator( 0 );
|
||||||
m_menu.Insert( 0, new wxMenuItem( &m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) );
|
m_menu.Insert( 0, new wxMenuItem( &m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) );
|
||||||
m_titleSet = true;
|
m_titleSet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ void CONTEXT_MENU::Add( const wxString& aLabel, int aId )
|
||||||
wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in"
|
wxLogWarning( wxT( "Adding more than one menu entry with the same ID may result in"
|
||||||
"undefined behaviour" ) );
|
"undefined behaviour" ) );
|
||||||
#endif
|
#endif
|
||||||
m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) );
|
m_menu.Append( new wxMenuItem( &m_menu, aId, aLabel, wxEmptyString, wxITEM_NORMAL ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ void CONTEXT_MENU::Add( const TOOL_ACTION& aAction )
|
||||||
|
|
||||||
if( aAction.HasHotKey() )
|
if( aAction.HasHotKey() )
|
||||||
menuEntry = wxString( ( aAction.GetMenuItem() + '\t' + getHotKeyDescription( aAction ) ).c_str(),
|
menuEntry = wxString( ( aAction.GetMenuItem() + '\t' + getHotKeyDescription( aAction ) ).c_str(),
|
||||||
wxConvUTF8 );
|
wxConvUTF8 );
|
||||||
else
|
else
|
||||||
menuEntry = wxString( aAction.GetMenuItem().c_str(), wxConvUTF8 );
|
menuEntry = wxString( aAction.GetMenuItem().c_str(), wxConvUTF8 );
|
||||||
|
|
||||||
|
@ -117,13 +117,13 @@ void CONTEXT_MENU::Add( const TOOL_ACTION& aAction )
|
||||||
|
|
||||||
void CONTEXT_MENU::Clear()
|
void CONTEXT_MENU::Clear()
|
||||||
{
|
{
|
||||||
m_titleSet = false;
|
m_titleSet = false;
|
||||||
|
|
||||||
// Remove all the entries from context menu
|
// Remove all the entries from context menu
|
||||||
for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i )
|
for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i )
|
||||||
m_menu.Destroy( m_menu.FindItemByPosition( 0 ) );
|
m_menu.Destroy( m_menu.FindItemByPosition( 0 ) );
|
||||||
|
|
||||||
m_toolActions.clear();
|
m_toolActions.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -27,23 +27,23 @@
|
||||||
|
|
||||||
KiGfx::VIEW* TOOL_BASE::getView() const
|
KiGfx::VIEW* TOOL_BASE::getView() const
|
||||||
{
|
{
|
||||||
return m_toolMgr->GetView();
|
return m_toolMgr->GetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
KiGfx::VIEW_CONTROLS* TOOL_BASE::getViewControls() const
|
KiGfx::VIEW_CONTROLS* TOOL_BASE::getViewControls() const
|
||||||
{
|
{
|
||||||
return m_toolMgr->GetViewControls();
|
return m_toolMgr->GetViewControls();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
wxWindow* TOOL_BASE::getEditFrameInt() const
|
wxWindow* TOOL_BASE::getEditFrameInt() const
|
||||||
{
|
{
|
||||||
return m_toolMgr->GetEditFrame();
|
return m_toolMgr->GetEditFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EDA_ITEM* TOOL_BASE::getModelInt() const
|
EDA_ITEM* TOOL_BASE::getModelInt() const
|
||||||
{
|
{
|
||||||
return m_toolMgr->GetModel();
|
return m_toolMgr->GetModel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,52 +42,52 @@ using boost::optional;
|
||||||
///> Stores information about a mouse button state
|
///> Stores information about a mouse button state
|
||||||
struct TOOL_DISPATCHER::ButtonState
|
struct TOOL_DISPATCHER::ButtonState
|
||||||
{
|
{
|
||||||
ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent,
|
ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent,
|
||||||
const wxEventType& aUpEvent ) :
|
const wxEventType& aUpEvent ) :
|
||||||
button( aButton ),
|
button( aButton ),
|
||||||
downEvent( aDownEvent ),
|
downEvent( aDownEvent ),
|
||||||
upEvent( aUpEvent )
|
upEvent( aUpEvent )
|
||||||
{};
|
{};
|
||||||
|
|
||||||
///> Flag indicating that dragging is active for the given button.
|
///> Flag indicating that dragging is active for the given button.
|
||||||
bool dragging;
|
bool dragging;
|
||||||
|
|
||||||
///> Flag indicating that the given button is pressed.
|
///> Flag indicating that the given button is pressed.
|
||||||
bool pressed;
|
bool pressed;
|
||||||
|
|
||||||
///> Point where dragging has started (in world coordinates).
|
|
||||||
VECTOR2D dragOrigin;
|
|
||||||
|
|
||||||
///> Point where click event has occurred.
|
///> Point where dragging has started (in world coordinates).
|
||||||
VECTOR2D downPosition;
|
VECTOR2D dragOrigin;
|
||||||
|
|
||||||
///> Difference between drag origin point and current mouse position (expressed as distance in
|
///> Point where click event has occurred.
|
||||||
///> pixels).
|
VECTOR2D downPosition;
|
||||||
double dragMaxDelta;
|
|
||||||
|
|
||||||
///> Determines the mouse button for which information are stored.
|
|
||||||
TOOL_MouseButtons button;
|
|
||||||
|
|
||||||
///> The type of wxEvent that determines mouse button press.
|
///> Difference between drag origin point and current mouse position (expressed as distance in
|
||||||
wxEventType downEvent;
|
///> pixels).
|
||||||
|
double dragMaxDelta;
|
||||||
|
|
||||||
///> The type of wxEvent that determines mouse button release.
|
///> Determines the mouse button for which information are stored.
|
||||||
wxEventType upEvent;
|
TOOL_MouseButtons button;
|
||||||
|
|
||||||
///> Time stamp for the last mouse button press event.
|
///> The type of wxEvent that determines mouse button press.
|
||||||
wxLongLong downTimestamp;
|
wxEventType downEvent;
|
||||||
|
|
||||||
///> Restores initial state.
|
///> The type of wxEvent that determines mouse button release.
|
||||||
void Reset()
|
wxEventType upEvent;
|
||||||
{
|
|
||||||
dragging = false;
|
///> Time stamp for the last mouse button press event.
|
||||||
pressed = false;
|
wxLongLong downTimestamp;
|
||||||
}
|
|
||||||
|
///> Restores initial state.
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
dragging = false;
|
||||||
|
pressed = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame ) :
|
TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditFrame ) :
|
||||||
m_toolMgr( aToolMgr ), m_editFrame( aEditFrame )
|
m_toolMgr( aToolMgr ), m_editFrame( aEditFrame )
|
||||||
{
|
{
|
||||||
m_buttons.push_back( new ButtonState( MB_Left, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP ) );
|
m_buttons.push_back( new ButtonState( MB_Left, wxEVT_LEFT_DOWN, wxEVT_LEFT_UP ) );
|
||||||
m_buttons.push_back( new ButtonState( MB_Right, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP ) );
|
m_buttons.push_back( new ButtonState( MB_Right, wxEVT_RIGHT_DOWN, wxEVT_RIGHT_UP ) );
|
||||||
|
@ -99,135 +99,135 @@ TOOL_DISPATCHER::TOOL_DISPATCHER( TOOL_MANAGER* aToolMgr, PCB_BASE_FRAME* aEditF
|
||||||
|
|
||||||
TOOL_DISPATCHER::~TOOL_DISPATCHER()
|
TOOL_DISPATCHER::~TOOL_DISPATCHER()
|
||||||
{
|
{
|
||||||
BOOST_FOREACH( ButtonState* st, m_buttons )
|
BOOST_FOREACH( ButtonState* st, m_buttons )
|
||||||
delete st;
|
delete st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_DISPATCHER::ResetState()
|
void TOOL_DISPATCHER::ResetState()
|
||||||
{
|
{
|
||||||
BOOST_FOREACH( ButtonState* st, m_buttons )
|
BOOST_FOREACH( ButtonState* st, m_buttons )
|
||||||
st->Reset();
|
st->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
KiGfx::VIEW* TOOL_DISPATCHER::getView()
|
KiGfx::VIEW* TOOL_DISPATCHER::getView()
|
||||||
{
|
{
|
||||||
return m_editFrame->GetGalCanvas()->GetView();
|
return m_editFrame->GetGalCanvas()->GetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion )
|
bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion )
|
||||||
{
|
{
|
||||||
ButtonState* st = m_buttons[aIndex];
|
ButtonState* st = m_buttons[aIndex];
|
||||||
wxEventType type = aEvent.GetEventType();
|
wxEventType type = aEvent.GetEventType();
|
||||||
optional<TOOL_EVENT> evt;
|
optional<TOOL_EVENT> evt;
|
||||||
bool isClick = false;
|
bool isClick = false;
|
||||||
|
|
||||||
bool up = type == st->upEvent;
|
bool up = type == st->upEvent;
|
||||||
bool down = type == st->downEvent;
|
bool down = type == st->downEvent;
|
||||||
|
|
||||||
int mods = decodeModifiers<wxMouseEvent>( static_cast<wxMouseEvent*>( &aEvent ) );
|
int mods = decodeModifiers<wxMouseEvent>( static_cast<wxMouseEvent*>( &aEvent ) );
|
||||||
int args = st->button | mods;
|
int args = st->button | mods;
|
||||||
|
|
||||||
if( down ) // Handle mouse button press
|
if( down ) // Handle mouse button press
|
||||||
{
|
{
|
||||||
st->downTimestamp = wxGetLocalTimeMillis();
|
st->downTimestamp = wxGetLocalTimeMillis();
|
||||||
st->dragOrigin = m_lastMousePos;
|
st->dragOrigin = m_lastMousePos;
|
||||||
st->downPosition = m_lastMousePos;
|
st->downPosition = m_lastMousePos;
|
||||||
st->dragMaxDelta = 0;
|
st->dragMaxDelta = 0;
|
||||||
st->pressed = true;
|
st->pressed = true;
|
||||||
evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args );
|
evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args );
|
||||||
}
|
}
|
||||||
else if( up ) // Handle mouse button release
|
else if( up ) // Handle mouse button release
|
||||||
{
|
{
|
||||||
st->pressed = false;
|
st->pressed = false;
|
||||||
|
|
||||||
if( st->dragging )
|
if( st->dragging )
|
||||||
{
|
{
|
||||||
wxLongLong t = wxGetLocalTimeMillis();
|
wxLongLong t = wxGetLocalTimeMillis();
|
||||||
|
|
||||||
// Determine if it was just a single click or beginning of dragging
|
// Determine if it was just a single click or beginning of dragging
|
||||||
if( t - st->downTimestamp < DragTimeThreshold &&
|
if( t - st->downTimestamp < DragTimeThreshold &&
|
||||||
st->dragMaxDelta < DragDistanceThreshold )
|
st->dragMaxDelta < DragDistanceThreshold )
|
||||||
isClick = true;
|
isClick = true;
|
||||||
else
|
else
|
||||||
evt = TOOL_EVENT( TC_Mouse, TA_MouseUp, args );
|
evt = TOOL_EVENT( TC_Mouse, TA_MouseUp, args );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
isClick = true;
|
isClick = true;
|
||||||
|
|
||||||
if( isClick )
|
|
||||||
evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args );
|
|
||||||
|
|
||||||
st->dragging = false;
|
if( isClick )
|
||||||
}
|
evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args );
|
||||||
|
|
||||||
if( st->pressed && aMotion )
|
st->dragging = false;
|
||||||
{
|
}
|
||||||
st->dragging = true;
|
|
||||||
double dragPixelDistance = getView()->ToScreen( m_lastMousePos - st->dragOrigin, false ).EuclideanNorm();
|
|
||||||
st->dragMaxDelta = std::max( st->dragMaxDelta, dragPixelDistance );
|
|
||||||
|
|
||||||
wxLongLong t = wxGetLocalTimeMillis();
|
if( st->pressed && aMotion )
|
||||||
|
{
|
||||||
|
st->dragging = true;
|
||||||
|
double dragPixelDistance = getView()->ToScreen( m_lastMousePos - st->dragOrigin, false ).EuclideanNorm();
|
||||||
|
st->dragMaxDelta = std::max( st->dragMaxDelta, dragPixelDistance );
|
||||||
|
|
||||||
if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold )
|
wxLongLong t = wxGetLocalTimeMillis();
|
||||||
{
|
|
||||||
evt = TOOL_EVENT( TC_Mouse, TA_MouseDrag, args );
|
|
||||||
evt->SetMouseDragOrigin( st->dragOrigin );
|
|
||||||
evt->SetMouseDelta( m_lastMousePos - st->dragOrigin );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( evt )
|
if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold )
|
||||||
{
|
{
|
||||||
evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
|
evt = TOOL_EVENT( TC_Mouse, TA_MouseDrag, args );
|
||||||
m_toolMgr->ProcessEvent( *evt );
|
evt->SetMouseDragOrigin( st->dragOrigin );
|
||||||
|
evt->SetMouseDelta( m_lastMousePos - st->dragOrigin );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
if( evt )
|
||||||
}
|
{
|
||||||
|
evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
|
||||||
|
m_toolMgr->ProcessEvent( *evt );
|
||||||
|
|
||||||
return false;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||||
{
|
{
|
||||||
bool motion = false, buttonEvents = false;
|
bool motion = false, buttonEvents = false;
|
||||||
optional<TOOL_EVENT> evt;
|
optional<TOOL_EVENT> evt;
|
||||||
|
|
||||||
int type = aEvent.GetEventType();
|
|
||||||
|
|
||||||
// Mouse handling
|
int type = aEvent.GetEventType();
|
||||||
if( type == wxEVT_MOTION || type == wxEVT_MOUSEWHEEL ||
|
|
||||||
type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
|
// Mouse handling
|
||||||
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
|
if( type == wxEVT_MOTION || type == wxEVT_MOUSEWHEEL ||
|
||||||
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP ||
|
type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
|
||||||
// Event issued whem mouse retains position in screen coordinates,
|
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
|
||||||
// but changes in world coordinates (eg. autopanning)
|
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP ||
|
||||||
type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
|
// Event issued whem mouse retains position in screen coordinates,
|
||||||
{
|
// but changes in world coordinates (eg. autopanning)
|
||||||
|
type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
|
||||||
|
{
|
||||||
VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition();
|
VECTOR2D screenPos = m_toolMgr->GetViewControls()->GetCursorPosition();
|
||||||
VECTOR2D pos = getView()->ToWorld( screenPos );
|
VECTOR2D pos = getView()->ToWorld( screenPos );
|
||||||
|
|
||||||
if( pos != m_lastMousePos || type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
|
if( pos != m_lastMousePos || type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
|
||||||
{
|
{
|
||||||
motion = true;
|
motion = true;
|
||||||
m_lastMousePos = pos;
|
m_lastMousePos = pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
for( unsigned int i = 0; i < m_buttons.size(); i++ )
|
for( unsigned int i = 0; i < m_buttons.size(); i++ )
|
||||||
buttonEvents |= handleMouseButton( aEvent, i, motion );
|
buttonEvents |= handleMouseButton( aEvent, i, motion );
|
||||||
|
|
||||||
if( !buttonEvents && motion )
|
if( !buttonEvents && motion )
|
||||||
{
|
{
|
||||||
evt = TOOL_EVENT( TC_Mouse, TA_MouseMotion );
|
evt = TOOL_EVENT( TC_Mouse, TA_MouseMotion );
|
||||||
evt->SetMousePosition( pos );
|
evt->SetMousePosition( pos );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keyboard handling
|
// Keyboard handling
|
||||||
else if( type == wxEVT_KEY_UP || type == wxEVT_KEY_DOWN )
|
else if( type == wxEVT_KEY_UP || type == wxEVT_KEY_DOWN )
|
||||||
{
|
{
|
||||||
wxKeyEvent* ke = static_cast<wxKeyEvent*>( &aEvent );
|
wxKeyEvent* ke = static_cast<wxKeyEvent*>( &aEvent );
|
||||||
int key = ke->GetKeyCode();
|
int key = ke->GetKeyCode();
|
||||||
|
@ -246,33 +246,33 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( evt )
|
if( evt )
|
||||||
m_toolMgr->ProcessEvent( *evt );
|
m_toolMgr->ProcessEvent( *evt );
|
||||||
|
|
||||||
// pass the event to the GUI, it might still be interested in it
|
// pass the event to the GUI, it might still be interested in it
|
||||||
aEvent.Skip();
|
aEvent.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent )
|
void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent )
|
||||||
{
|
{
|
||||||
bool activateTool = false;
|
bool activateTool = false;
|
||||||
std::string toolName;
|
std::string toolName;
|
||||||
|
|
||||||
// fixme: use TOOL_ACTIONs here
|
|
||||||
switch( aEvent.GetId() )
|
|
||||||
{
|
|
||||||
case ID_PNS_ROUTER_TOOL:
|
|
||||||
toolName = "pcbnew.InteractiveRouter";
|
|
||||||
activateTool = true;
|
|
||||||
break;
|
|
||||||
case ID_SELECTION_TOOL:
|
|
||||||
toolName = "pcbnew.InteractiveSelection";
|
|
||||||
activateTool = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// do nothing if the legacy view is active
|
// fixme: use TOOL_ACTIONs here
|
||||||
if( activateTool && m_editFrame->IsGalCanvasActive() )
|
switch( aEvent.GetId() )
|
||||||
m_toolMgr->InvokeTool( toolName );
|
{
|
||||||
|
case ID_PNS_ROUTER_TOOL:
|
||||||
|
toolName = "pcbnew.InteractiveRouter";
|
||||||
|
activateTool = true;
|
||||||
|
break;
|
||||||
|
case ID_SELECTION_TOOL:
|
||||||
|
toolName = "pcbnew.InteractiveSelection";
|
||||||
|
activateTool = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do nothing if the legacy view is active
|
||||||
|
if( activateTool && m_editFrame->IsGalCanvasActive() )
|
||||||
|
m_toolMgr->InvokeTool( toolName );
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,22 +35,22 @@ using namespace std;
|
||||||
|
|
||||||
struct FlagString
|
struct FlagString
|
||||||
{
|
{
|
||||||
int flag;
|
int flag;
|
||||||
std::string str;
|
std::string str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static const std::string flag2string( int flag, const FlagString* exps )
|
static const std::string flag2string( int flag, const FlagString* exps )
|
||||||
{
|
{
|
||||||
std::string rv;
|
std::string rv;
|
||||||
|
|
||||||
for( int i = 0; exps[i].str.length(); i++ )
|
for( int i = 0; exps[i].str.length(); i++ )
|
||||||
{
|
{
|
||||||
if( exps[i].flag & flag )
|
if( exps[i].flag & flag )
|
||||||
rv += exps[i].str + " ";
|
rv += exps[i].str + " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,97 +62,97 @@ bool TOOL_EVENT::IsAction( const TOOL_ACTION* aAction ) const
|
||||||
|
|
||||||
const std::string TOOL_EVENT::Format() const
|
const std::string TOOL_EVENT::Format() const
|
||||||
{
|
{
|
||||||
std::string ev;
|
std::string ev;
|
||||||
|
|
||||||
const FlagString categories[] = {
|
const FlagString categories[] = {
|
||||||
{ TC_Mouse, "mouse" },
|
{ TC_Mouse, "mouse" },
|
||||||
{ TC_Keyboard, "keyboard" },
|
{ TC_Keyboard, "keyboard" },
|
||||||
{ TC_Command, "command" },
|
{ TC_Command, "command" },
|
||||||
{ TC_Message, "message" },
|
{ TC_Message, "message" },
|
||||||
{ TC_View, "view" },
|
{ TC_View, "view" },
|
||||||
{ 0, "" }
|
{ 0, "" }
|
||||||
};
|
};
|
||||||
|
|
||||||
const FlagString actions[] = {
|
const FlagString actions[] = {
|
||||||
{ TA_MouseClick, "click" },
|
{ TA_MouseClick, "click" },
|
||||||
{ TA_MouseUp, "button-up" },
|
{ TA_MouseUp, "button-up" },
|
||||||
{ TA_MouseDown, "button-down" },
|
{ TA_MouseDown, "button-down" },
|
||||||
{ TA_MouseDrag, "drag" },
|
{ TA_MouseDrag, "drag" },
|
||||||
{ TA_MouseMotion, "motion" },
|
{ TA_MouseMotion, "motion" },
|
||||||
{ TA_MouseWheel, "wheel" },
|
{ TA_MouseWheel, "wheel" },
|
||||||
{ TA_KeyUp, "key-up" },
|
{ TA_KeyUp, "key-up" },
|
||||||
{ TA_KeyDown, "key-down" },
|
{ TA_KeyDown, "key-down" },
|
||||||
{ TA_ViewRefresh, "view-refresh" },
|
{ TA_ViewRefresh, "view-refresh" },
|
||||||
{ TA_ViewZoom, "view-zoom" },
|
{ TA_ViewZoom, "view-zoom" },
|
||||||
{ TA_ViewPan, "view-pan" },
|
{ TA_ViewPan, "view-pan" },
|
||||||
{ TA_ViewDirty, "view-dirty" },
|
{ TA_ViewDirty, "view-dirty" },
|
||||||
{ TA_ChangeLayer, "change-layer" },
|
{ TA_ChangeLayer, "change-layer" },
|
||||||
{ TA_CancelTool, "cancel-tool" },
|
{ TA_CancelTool, "cancel-tool" },
|
||||||
{ TA_ContextMenuUpdate, "context-menu-update" },
|
{ TA_ContextMenuUpdate, "context-menu-update" },
|
||||||
{ TA_ContextMenuChoice, "context-menu-choice" },
|
{ TA_ContextMenuChoice, "context-menu-choice" },
|
||||||
{ TA_Action, "action" },
|
{ TA_Action, "action" },
|
||||||
{ 0, "" }
|
{ 0, "" }
|
||||||
};
|
};
|
||||||
|
|
||||||
const FlagString buttons[] = {
|
const FlagString buttons[] = {
|
||||||
{ MB_None, "none" },
|
{ MB_None, "none" },
|
||||||
{ MB_Left, "left" },
|
{ MB_Left, "left" },
|
||||||
{ MB_Right, "right" },
|
{ MB_Right, "right" },
|
||||||
{ MB_Middle, "middle" },
|
{ MB_Middle, "middle" },
|
||||||
{ 0, "" }
|
{ 0, "" }
|
||||||
};
|
};
|
||||||
|
|
||||||
const FlagString modifiers[] = {
|
const FlagString modifiers[] = {
|
||||||
{ MD_ModShift, "shift" },
|
{ MD_ModShift, "shift" },
|
||||||
{ MD_ModCtrl, "ctrl" },
|
{ MD_ModCtrl, "ctrl" },
|
||||||
{ MD_ModAlt, "alt" },
|
{ MD_ModAlt, "alt" },
|
||||||
{ 0, "" }
|
{ 0, "" }
|
||||||
};
|
};
|
||||||
|
|
||||||
ev = "category: ";
|
ev = "category: ";
|
||||||
ev += flag2string( m_category, categories );
|
ev += flag2string( m_category, categories );
|
||||||
ev += " action: ";
|
ev += " action: ";
|
||||||
ev += flag2string( m_actions, actions );
|
ev += flag2string( m_actions, actions );
|
||||||
|
|
||||||
if( m_actions & TA_Mouse )
|
|
||||||
{
|
|
||||||
ev += " btns: ";
|
|
||||||
ev += flag2string( m_mouseButtons, buttons );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( m_actions & TA_Keyboard )
|
if( m_actions & TA_Mouse )
|
||||||
{
|
{
|
||||||
|
ev += " btns: ";
|
||||||
|
ev += flag2string( m_mouseButtons, buttons );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_actions & TA_Keyboard )
|
||||||
|
{
|
||||||
char tmp[128];
|
char tmp[128];
|
||||||
sprintf( tmp, "key: %d", m_keyCode );
|
sprintf( tmp, "key: %d", m_keyCode );
|
||||||
ev += tmp;
|
ev += tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_actions & ( TA_Mouse | TA_Keyboard ) )
|
|
||||||
{
|
|
||||||
ev += " mods: ";
|
|
||||||
ev += flag2string( m_modifiers, modifiers );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( m_commandId )
|
if( m_actions & ( TA_Mouse | TA_Keyboard ) )
|
||||||
{
|
{
|
||||||
char tmp[128];
|
ev += " mods: ";
|
||||||
sprintf( tmp, "cmd-id: %d", *m_commandId );
|
ev += flag2string( m_modifiers, modifiers );
|
||||||
ev += tmp;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if( m_commandStr )
|
if( m_commandId )
|
||||||
ev += "cmd-str: " + ( *m_commandStr );
|
{
|
||||||
|
char tmp[128];
|
||||||
return ev;
|
sprintf( tmp, "cmd-id: %d", *m_commandId );
|
||||||
|
ev += tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_commandStr )
|
||||||
|
ev += "cmd-str: " + ( *m_commandStr );
|
||||||
|
|
||||||
|
return ev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::string TOOL_EVENT_LIST::Format() const
|
const std::string TOOL_EVENT_LIST::Format() const
|
||||||
{
|
{
|
||||||
string s;
|
string s;
|
||||||
|
|
||||||
BOOST_FOREACH( TOOL_EVENT e, m_events )
|
BOOST_FOREACH( TOOL_EVENT e, m_events )
|
||||||
s += e.Format() + " ";
|
s += e.Format() + " ";
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,13 @@
|
||||||
#include <tool/context_menu.h>
|
#include <tool/context_menu.h>
|
||||||
|
|
||||||
TOOL_INTERACTIVE::TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName ) :
|
TOOL_INTERACTIVE::TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName ) :
|
||||||
TOOL_BASE( TOOL_Interactive, aId, aName )
|
TOOL_BASE( TOOL_Interactive, aId, aName )
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
|
||||||
TOOL_INTERACTIVE::TOOL_INTERACTIVE( const std::string& aName ) :
|
TOOL_INTERACTIVE::TOOL_INTERACTIVE( const std::string& aName ) :
|
||||||
TOOL_BASE( TOOL_Interactive, TOOL_MANAGER::MakeToolId( aName ), aName )
|
TOOL_BASE( TOOL_Interactive, TOOL_MANAGER::MakeToolId( aName ), aName )
|
||||||
{};
|
{};
|
||||||
|
|
||||||
|
|
||||||
TOOL_INTERACTIVE::~TOOL_INTERACTIVE()
|
TOOL_INTERACTIVE::~TOOL_INTERACTIVE()
|
||||||
|
@ -46,18 +46,18 @@ TOOL_INTERACTIVE::~TOOL_INTERACTIVE()
|
||||||
|
|
||||||
OPT_TOOL_EVENT TOOL_INTERACTIVE::Wait( const TOOL_EVENT_LIST& aEventList )
|
OPT_TOOL_EVENT TOOL_INTERACTIVE::Wait( const TOOL_EVENT_LIST& aEventList )
|
||||||
{
|
{
|
||||||
return m_toolMgr->ScheduleWait( this, aEventList );
|
return m_toolMgr->ScheduleWait( this, aEventList );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_INTERACTIVE::goInternal( TOOL_STATE_FUNC& aState, const TOOL_EVENT_LIST& aConditions )
|
void TOOL_INTERACTIVE::goInternal( TOOL_STATE_FUNC& aState, const TOOL_EVENT_LIST& aConditions )
|
||||||
{
|
{
|
||||||
m_toolMgr->ScheduleNextState( this, aState, aConditions );
|
m_toolMgr->ScheduleNextState( this, aState, aConditions );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_INTERACTIVE::SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger )
|
void TOOL_INTERACTIVE::SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger )
|
||||||
{
|
{
|
||||||
aMenu->setTool( this );
|
aMenu->setTool( this );
|
||||||
m_toolMgr->ScheduleContextMenu( this, aMenu, aTrigger );
|
m_toolMgr->ScheduleContextMenu( this, aMenu, aTrigger );
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,50 +52,50 @@ using namespace std;
|
||||||
struct TOOL_MANAGER::TOOL_STATE
|
struct TOOL_MANAGER::TOOL_STATE
|
||||||
{
|
{
|
||||||
/// The tool itself
|
/// The tool itself
|
||||||
TOOL_BASE* theTool;
|
TOOL_BASE* theTool;
|
||||||
|
|
||||||
/// Is the tool active (pending execution) or disabled at the moment
|
|
||||||
bool idle;
|
|
||||||
|
|
||||||
/// Flag defining if the tool is waiting for any event (i.e. if it
|
/// Is the tool active (pending execution) or disabled at the moment
|
||||||
/// issued a Wait() call).
|
bool idle;
|
||||||
bool pendingWait;
|
|
||||||
|
|
||||||
/// Is there a context menu being displayed
|
/// Flag defining if the tool is waiting for any event (i.e. if it
|
||||||
bool pendingContextMenu;
|
/// issued a Wait() call).
|
||||||
|
bool pendingWait;
|
||||||
|
|
||||||
/// Context menu currently used by the tool
|
/// Is there a context menu being displayed
|
||||||
CONTEXT_MENU* contextMenu;
|
bool pendingContextMenu;
|
||||||
|
|
||||||
/// Defines when the context menu is opened
|
/// Context menu currently used by the tool
|
||||||
CONTEXT_MENU_TRIGGER contextMenuTrigger;
|
CONTEXT_MENU* contextMenu;
|
||||||
|
|
||||||
/// Tool execution context
|
/// Defines when the context menu is opened
|
||||||
COROUTINE<int, TOOL_EVENT&>* cofunc;
|
CONTEXT_MENU_TRIGGER contextMenuTrigger;
|
||||||
|
|
||||||
/// The event that triggered the execution/wakeup of the tool after Wait() call
|
|
||||||
TOOL_EVENT wakeupEvent;
|
|
||||||
|
|
||||||
/// List of events the tool is currently waiting for
|
/// Tool execution context
|
||||||
TOOL_EVENT_LIST waitEvents;
|
COROUTINE<int, TOOL_EVENT&>* cofunc;
|
||||||
|
|
||||||
/// List of possible transitions (ie. association of events and state handlers that are executed
|
/// The event that triggered the execution/wakeup of the tool after Wait() call
|
||||||
/// upon the event reception
|
TOOL_EVENT wakeupEvent;
|
||||||
std::vector<TRANSITION> transitions;
|
|
||||||
|
|
||||||
bool operator==( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
|
/// List of events the tool is currently waiting for
|
||||||
|
TOOL_EVENT_LIST waitEvents;
|
||||||
|
|
||||||
|
/// List of possible transitions (ie. association of events and state handlers that are executed
|
||||||
|
/// upon the event reception
|
||||||
|
std::vector<TRANSITION> transitions;
|
||||||
|
|
||||||
|
bool operator==( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
|
||||||
{
|
{
|
||||||
return ( aRhs.theTool == this->theTool );
|
return ( aRhs.theTool == this->theTool );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
|
bool operator!=( const TOOL_MANAGER::TOOL_STATE& aRhs ) const
|
||||||
{
|
{
|
||||||
return ( aRhs.theTool != this->theTool );
|
return ( aRhs.theTool != this->theTool );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TOOL_MANAGER::TOOL_MANAGER() :
|
TOOL_MANAGER::TOOL_MANAGER() :
|
||||||
m_model( NULL ), m_view( NULL )
|
m_model( NULL ), m_view( NULL )
|
||||||
{
|
{
|
||||||
m_actionMgr = new ACTION_MANAGER( this );
|
m_actionMgr = new ACTION_MANAGER( this );
|
||||||
|
@ -119,37 +119,37 @@ TOOL_MANAGER::~TOOL_MANAGER()
|
||||||
|
|
||||||
void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool )
|
void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool )
|
||||||
{
|
{
|
||||||
TOOL_STATE* st = new TOOL_STATE;
|
TOOL_STATE* st = new TOOL_STATE;
|
||||||
|
|
||||||
st->theTool = aTool;
|
st->theTool = aTool;
|
||||||
st->idle = true;
|
st->idle = true;
|
||||||
st->pendingWait = false;
|
st->pendingWait = false;
|
||||||
st->pendingContextMenu = false;
|
st->pendingContextMenu = false;
|
||||||
st->cofunc = NULL;
|
st->cofunc = NULL;
|
||||||
st->contextMenuTrigger = CMENU_OFF;
|
st->contextMenuTrigger = CMENU_OFF;
|
||||||
|
|
||||||
m_toolState[aTool] = st;
|
m_toolState[aTool] = st;
|
||||||
m_toolNameIndex[aTool->GetName()] = st;
|
m_toolNameIndex[aTool->GetName()] = st;
|
||||||
m_toolIdIndex[aTool->GetId()] = st;
|
m_toolIdIndex[aTool->GetId()] = st;
|
||||||
|
|
||||||
aTool->m_toolMgr = this;
|
|
||||||
|
|
||||||
if( aTool->GetType() == TOOL_Interactive )
|
|
||||||
{
|
|
||||||
bool initState = static_cast<TOOL_INTERACTIVE*>( aTool )->Init();
|
|
||||||
if( !initState )
|
|
||||||
{
|
|
||||||
wxLogError( wxT( "Initialization of the %s tool failed" ), aTool->GetName().c_str() );
|
|
||||||
|
|
||||||
// Unregister the tool
|
aTool->m_toolMgr = this;
|
||||||
m_toolState.erase( aTool );
|
|
||||||
m_toolNameIndex.erase( aTool->GetName() );
|
|
||||||
m_toolIdIndex.erase( aTool->GetId() );
|
|
||||||
|
|
||||||
delete st;
|
if( aTool->GetType() == TOOL_Interactive )
|
||||||
delete aTool;
|
{
|
||||||
}
|
bool initState = static_cast<TOOL_INTERACTIVE*>( aTool )->Init();
|
||||||
}
|
if( !initState )
|
||||||
|
{
|
||||||
|
wxLogError( wxT( "Initialization of the %s tool failed" ), aTool->GetName().c_str() );
|
||||||
|
|
||||||
|
// Unregister the tool
|
||||||
|
m_toolState.erase( aTool );
|
||||||
|
m_toolNameIndex.erase( aTool->GetName() );
|
||||||
|
m_toolIdIndex.erase( aTool->GetId() );
|
||||||
|
|
||||||
|
delete st;
|
||||||
|
delete aTool;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -268,89 +268,89 @@ TOOL_BASE* TOOL_MANAGER::FindTool( const std::string& aName ) const
|
||||||
void TOOL_MANAGER::ScheduleNextState( TOOL_BASE* aTool, TOOL_STATE_FUNC& aHandler,
|
void TOOL_MANAGER::ScheduleNextState( TOOL_BASE* aTool, TOOL_STATE_FUNC& aHandler,
|
||||||
const TOOL_EVENT_LIST& aConditions )
|
const TOOL_EVENT_LIST& aConditions )
|
||||||
{
|
{
|
||||||
TOOL_STATE* st = m_toolState[aTool];
|
TOOL_STATE* st = m_toolState[aTool];
|
||||||
st->transitions.push_back( TRANSITION( aConditions, aHandler ) );
|
st->transitions.push_back( TRANSITION( aConditions, aHandler ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
optional<TOOL_EVENT> TOOL_MANAGER::ScheduleWait( TOOL_BASE* aTool,
|
optional<TOOL_EVENT> TOOL_MANAGER::ScheduleWait( TOOL_BASE* aTool,
|
||||||
const TOOL_EVENT_LIST& aConditions )
|
const TOOL_EVENT_LIST& aConditions )
|
||||||
{
|
{
|
||||||
TOOL_STATE* st = m_toolState[aTool];
|
TOOL_STATE* st = m_toolState[aTool];
|
||||||
|
|
||||||
// indicate to the manager that we are going to sleep and we shall be
|
|
||||||
// woken up when an event matching aConditions arrive
|
|
||||||
st->pendingWait = true;
|
|
||||||
st->waitEvents = aConditions;
|
|
||||||
|
|
||||||
// switch context back to event dispatcher loop
|
// indicate to the manager that we are going to sleep and we shall be
|
||||||
st->cofunc->Yield();
|
// woken up when an event matching aConditions arrive
|
||||||
|
st->pendingWait = true;
|
||||||
|
st->waitEvents = aConditions;
|
||||||
|
|
||||||
return st->wakeupEvent;
|
// switch context back to event dispatcher loop
|
||||||
|
st->cofunc->Yield();
|
||||||
|
|
||||||
|
return st->wakeupEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
|
void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
// iterate over all registered tools
|
// iterate over all registered tools
|
||||||
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
|
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
|
||||||
{
|
{
|
||||||
TOOL_STATE* st = m_toolIdIndex[toolId];
|
TOOL_STATE* st = m_toolIdIndex[toolId];
|
||||||
|
|
||||||
// the tool state handler is waiting for events (i.e. called Wait() method)
|
// the tool state handler is waiting for events (i.e. called Wait() method)
|
||||||
if( st->pendingWait )
|
if( st->pendingWait )
|
||||||
{
|
{
|
||||||
if( st->waitEvents.Matches( aEvent ) )
|
if( st->waitEvents.Matches( aEvent ) )
|
||||||
{
|
{
|
||||||
// By default, already processed events are not passed further
|
// By default, already processed events are not passed further
|
||||||
m_passEvent = false;
|
m_passEvent = false;
|
||||||
|
|
||||||
// got matching event? clear wait list and wake up the coroutine
|
// got matching event? clear wait list and wake up the coroutine
|
||||||
st->wakeupEvent = aEvent;
|
st->wakeupEvent = aEvent;
|
||||||
st->pendingWait = false;
|
st->pendingWait = false;
|
||||||
st->waitEvents.clear();
|
st->waitEvents.clear();
|
||||||
if( st->cofunc && !st->cofunc->Resume() )
|
if( st->cofunc && !st->cofunc->Resume() )
|
||||||
finishTool( st ); // The couroutine has finished
|
finishTool( st ); // The couroutine has finished
|
||||||
|
|
||||||
// If the tool did not request to propagate
|
// If the tool did not request to propagate
|
||||||
// the event to other tools, we should stop it now
|
// the event to other tools, we should stop it now
|
||||||
if( !m_passEvent )
|
if( !m_passEvent )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values )
|
BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values )
|
||||||
{
|
{
|
||||||
// the tool scheduled next state(s) by calling Go()
|
// the tool scheduled next state(s) by calling Go()
|
||||||
if( !st->pendingWait )
|
if( !st->pendingWait )
|
||||||
{
|
{
|
||||||
// no state handler in progress - check if there are any transitions (defined by
|
// no state handler in progress - check if there are any transitions (defined by
|
||||||
// Go() method that match the event.
|
// Go() method that match the event.
|
||||||
if( st->transitions.size() )
|
if( st->transitions.size() )
|
||||||
{
|
{
|
||||||
BOOST_FOREACH( TRANSITION tr, st->transitions )
|
BOOST_FOREACH( TRANSITION tr, st->transitions )
|
||||||
{
|
{
|
||||||
if( tr.first.Matches( aEvent ) )
|
if( tr.first.Matches( aEvent ) )
|
||||||
{
|
{
|
||||||
st->transitions.clear();
|
st->transitions.clear();
|
||||||
|
|
||||||
// no tool context allocated yet? Create one.
|
// no tool context allocated yet? Create one.
|
||||||
if( !st->cofunc )
|
if( !st->cofunc )
|
||||||
st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second );
|
st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second );
|
||||||
else
|
else
|
||||||
st->cofunc->SetEntry( tr.second );
|
st->cofunc->SetEntry( tr.second );
|
||||||
|
|
||||||
// got match? Run the handler.
|
// got match? Run the handler.
|
||||||
st->cofunc->Call( aEvent );
|
st->cofunc->Call( aEvent );
|
||||||
|
|
||||||
if( !st->cofunc->Running() )
|
if( !st->cofunc->Running() )
|
||||||
finishTool( st ); // The couroutine has finished immediately?
|
finishTool( st ); // The couroutine has finished immediately?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -411,90 +411,90 @@ void TOOL_MANAGER::finishTool( TOOL_STATE* aState )
|
||||||
|
|
||||||
bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent )
|
bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
// wxLogDebug( "event: %s", aEvent.Format().c_str() );
|
// wxLogDebug( "event: %s", aEvent.Format().c_str() );
|
||||||
|
|
||||||
// Early dispatch of events destined for the TOOL_MANAGER
|
// Early dispatch of events destined for the TOOL_MANAGER
|
||||||
if( !dispatchStandardEvents( aEvent ) )
|
if( !dispatchStandardEvents( aEvent ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
dispatchInternal( aEvent );
|
dispatchInternal( aEvent );
|
||||||
|
|
||||||
// popup menu handling
|
// popup menu handling
|
||||||
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
|
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
|
||||||
{
|
{
|
||||||
TOOL_STATE* st = m_toolIdIndex[toolId];
|
TOOL_STATE* st = m_toolIdIndex[toolId];
|
||||||
|
|
||||||
// the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
|
// the tool requested a context menu. The menu is activated on RMB click (CMENU_BUTTON mode)
|
||||||
// or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
|
// or immediately (CMENU_NOW) mode. The latter is used for clarification lists.
|
||||||
if( st->contextMenuTrigger != CMENU_OFF )
|
if( st->contextMenuTrigger != CMENU_OFF )
|
||||||
{
|
{
|
||||||
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( MB_Right ) )
|
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( MB_Right ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
st->pendingWait = true;
|
st->pendingWait = true;
|
||||||
st->waitEvents = TOOL_EVENT( TC_Any, TA_Any );
|
st->waitEvents = TOOL_EVENT( TC_Any, TA_Any );
|
||||||
|
|
||||||
if( st->contextMenuTrigger == CMENU_NOW )
|
if( st->contextMenuTrigger == CMENU_NOW )
|
||||||
st->contextMenuTrigger = CMENU_OFF;
|
st->contextMenuTrigger = CMENU_OFF;
|
||||||
|
|
||||||
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
|
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
|
||||||
GetEditFrame()->PopupMenu( menu->GetMenu() );
|
GetEditFrame()->PopupMenu( menu->GetMenu() );
|
||||||
|
|
||||||
//
|
//
|
||||||
TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
|
TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
|
||||||
dispatchInternal( evt );
|
dispatchInternal( evt );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( m_view->IsDirty() )
|
if( m_view->IsDirty() )
|
||||||
{
|
{
|
||||||
PCB_EDIT_FRAME* f = static_cast<PCB_EDIT_FRAME*>( GetEditFrame() );
|
PCB_EDIT_FRAME* f = static_cast<PCB_EDIT_FRAME*>( GetEditFrame() );
|
||||||
f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER.
|
f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER.
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_MANAGER::ScheduleContextMenu( TOOL_BASE* aTool, CONTEXT_MENU* aMenu,
|
void TOOL_MANAGER::ScheduleContextMenu( TOOL_BASE* aTool, CONTEXT_MENU* aMenu,
|
||||||
CONTEXT_MENU_TRIGGER aTrigger )
|
CONTEXT_MENU_TRIGGER aTrigger )
|
||||||
{
|
{
|
||||||
TOOL_STATE* st = m_toolState[aTool];
|
TOOL_STATE* st = m_toolState[aTool];
|
||||||
|
|
||||||
st->contextMenu = aMenu;
|
st->contextMenu = aMenu;
|
||||||
st->contextMenuTrigger = aTrigger;
|
st->contextMenuTrigger = aTrigger;
|
||||||
|
|
||||||
// the tool wants the menu immediately? Preempt it and do so :)
|
// the tool wants the menu immediately? Preempt it and do so :)
|
||||||
if( aTrigger == CMENU_NOW )
|
if( aTrigger == CMENU_NOW )
|
||||||
st->cofunc->Yield();
|
st->cofunc->Yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
|
TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
|
||||||
{
|
{
|
||||||
static int currentId;
|
static int currentId;
|
||||||
return currentId++;
|
return currentId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TOOL_MANAGER::SetEnvironment( EDA_ITEM* aModel, KiGfx::VIEW* aView,
|
void TOOL_MANAGER::SetEnvironment( EDA_ITEM* aModel, KiGfx::VIEW* aView,
|
||||||
KiGfx::VIEW_CONTROLS* aViewControls, wxWindow* aFrame )
|
KiGfx::VIEW_CONTROLS* aViewControls, wxWindow* aFrame )
|
||||||
{
|
{
|
||||||
m_model = aModel;
|
m_model = aModel;
|
||||||
m_view = aView;
|
m_view = aView;
|
||||||
m_viewControls = aViewControls;
|
m_viewControls = aViewControls;
|
||||||
m_editFrame = aFrame;
|
m_editFrame = aFrame;
|
||||||
|
|
||||||
// Reset state of the registered tools
|
// Reset state of the registered tools
|
||||||
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
|
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
|
||||||
{
|
{
|
||||||
TOOL_BASE* tool = m_toolIdIndex[toolId]->theTool;
|
TOOL_BASE* tool = m_toolIdIndex[toolId]->theTool;
|
||||||
|
|
||||||
if( tool->GetType() == TOOL_Interactive )
|
if( tool->GetType() == TOOL_Interactive )
|
||||||
static_cast<TOOL_INTERACTIVE*>( tool )->Reset();
|
static_cast<TOOL_INTERACTIVE*>( tool )->Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ public:
|
||||||
{
|
{
|
||||||
return m_view;
|
return m_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetViewControls()
|
* Function GetViewControls()
|
||||||
* Returns a pointer to the VIEW_CONTROLS instance used in the panel.
|
* Returns a pointer to the VIEW_CONTROLS instance used in the panel.
|
||||||
|
|
|
@ -131,7 +131,7 @@ public:
|
||||||
* Saturates the color to a given factor (in HSV model)
|
* Saturates the color to a given factor (in HSV model)
|
||||||
*/
|
*/
|
||||||
COLOR4D& Saturate( double aFactor );
|
COLOR4D& Saturate( double aFactor );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Brightened
|
* Function Brightened
|
||||||
* Returns a color that is brighter by a given factor, without modifying object.
|
* Returns a color that is brighter by a given factor, without modifying object.
|
||||||
|
|
|
@ -172,11 +172,11 @@ private:
|
||||||
void programInfo( GLuint aProgram );
|
void programInfo( GLuint aProgram );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the shader information.
|
* @brief Get the shader information.
|
||||||
*
|
*
|
||||||
* @param aShader is the shader number.
|
* @param aShader is the shader number.
|
||||||
*/
|
*/
|
||||||
void shaderInfo( GLuint aShader );
|
void shaderInfo( GLuint aShader );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the shader source file
|
* @brief Read the shader source file
|
||||||
|
|
|
@ -36,278 +36,278 @@ typedef boost::optional<VECTOR2I> OPT_VECTOR2I;
|
||||||
|
|
||||||
class SEG
|
class SEG
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
typedef VECTOR2I::extended_type ecoord;
|
typedef VECTOR2I::extended_type ecoord;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
friend inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg );
|
friend inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg );
|
||||||
|
|
||||||
/* Start and the of the segment. Public, to make access simpler. These are references
|
/* Start and the of the segment. Public, to make access simpler. These are references
|
||||||
* to an object the segment belongs to (e.g. a line chain) or references to locally stored points
|
* to an object the segment belongs to (e.g. a line chain) or references to locally stored points
|
||||||
* (m_a, m_b).
|
* (m_a, m_b).
|
||||||
*/
|
*/
|
||||||
VECTOR2I& a, b;
|
VECTOR2I& a, b;
|
||||||
|
|
||||||
/** Default constructor
|
/** Default constructor
|
||||||
* Creates an empty (0, 0) segment, locally-referenced
|
* Creates an empty (0, 0) segment, locally-referenced
|
||||||
*/
|
*/
|
||||||
SEG() : a( m_a ), b( m_b )
|
SEG() : a( m_a ), b( m_b )
|
||||||
{
|
{
|
||||||
a = m_a;
|
a = m_a;
|
||||||
b = m_b;
|
b = m_b;
|
||||||
m_is_local = true;
|
m_is_local = true;
|
||||||
m_index = -1;
|
m_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* Creates a segment between (aX1, aY1) and (aX2, aY2), locally referenced
|
* Creates a segment between (aX1, aY1) and (aX2, aY2), locally referenced
|
||||||
*/
|
*/
|
||||||
SEG( int aX1, int aY1, int aX2, int aY2 ) : a( m_a ), b( m_b )
|
SEG( int aX1, int aY1, int aX2, int aY2 ) : a( m_a ), b( m_b )
|
||||||
{
|
{
|
||||||
m_a = VECTOR2I( aX1, aY1 );
|
m_a = VECTOR2I( aX1, aY1 );
|
||||||
m_b = VECTOR2I( aX2, aY2 );
|
m_b = VECTOR2I( aX2, aY2 );
|
||||||
a = m_a;
|
a = m_a;
|
||||||
b = m_b;
|
b = m_b;
|
||||||
m_is_local = true;
|
m_is_local = true;
|
||||||
m_index = -1;
|
m_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* Creates a segment between (aA) and (aB), locally referenced
|
* Creates a segment between (aA) and (aB), locally referenced
|
||||||
*/
|
*/
|
||||||
SEG( const VECTOR2I& aA, const VECTOR2I& aB ) : a( m_a ), b( m_b ), m_a( aA ), m_b( aB )
|
SEG( const VECTOR2I& aA, const VECTOR2I& aB ) : a( m_a ), b( m_b ), m_a( aA ), m_b( aB )
|
||||||
{
|
{
|
||||||
a = m_a;
|
a = m_a;
|
||||||
b = m_b;
|
b = m_b;
|
||||||
m_is_local = true;
|
m_is_local = true;
|
||||||
m_index = -1;
|
m_index = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* Creates a segment between (aA) and (aB), referenced to a multi-segment shape
|
|
||||||
* @param aA reference to the start point in the parent shape
|
|
||||||
* @param aB reference to the end point in the parent shape
|
|
||||||
* @param aIndex index of the segment within the parent shape
|
|
||||||
*/
|
|
||||||
SEG ( VECTOR2I& aA, VECTOR2I& aB, int aIndex ) : a( aA ), b( aB )
|
|
||||||
{
|
|
||||||
m_is_local = false;
|
|
||||||
m_index = aIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor
|
* Constructor
|
||||||
*/
|
* Creates a segment between (aA) and (aB), referenced to a multi-segment shape
|
||||||
SEG ( const SEG& aSeg ) : a( m_a ), b( m_b )
|
* @param aA reference to the start point in the parent shape
|
||||||
{
|
* @param aB reference to the end point in the parent shape
|
||||||
if (aSeg.m_is_local)
|
* @param aIndex index of the segment within the parent shape
|
||||||
{
|
*/
|
||||||
m_a = aSeg.m_a;
|
SEG ( VECTOR2I& aA, VECTOR2I& aB, int aIndex ) : a( aA ), b( aB )
|
||||||
m_b = aSeg.m_b;
|
{
|
||||||
a = m_a;
|
m_is_local = false;
|
||||||
b = m_b;
|
m_index = aIndex;
|
||||||
m_is_local = true;
|
}
|
||||||
m_index = -1;
|
|
||||||
} else {
|
|
||||||
a = aSeg.a;
|
|
||||||
b = aSeg.b;
|
|
||||||
m_index = aSeg.m_index;
|
|
||||||
m_is_local = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SEG& operator=( const SEG& aSeg )
|
/**
|
||||||
{
|
* Copy constructor
|
||||||
a = aSeg.a;
|
*/
|
||||||
b = aSeg.b;
|
SEG ( const SEG& aSeg ) : a( m_a ), b( m_b )
|
||||||
m_a = aSeg.m_a;
|
{
|
||||||
m_b = aSeg.m_b;
|
if (aSeg.m_is_local)
|
||||||
m_index = aSeg.m_index;
|
{
|
||||||
m_is_local = aSeg.m_is_local;
|
m_a = aSeg.m_a;
|
||||||
return *this;
|
m_b = aSeg.m_b;
|
||||||
}
|
a = m_a;
|
||||||
|
b = m_b;
|
||||||
|
m_is_local = true;
|
||||||
|
m_index = -1;
|
||||||
|
} else {
|
||||||
|
a = aSeg.a;
|
||||||
|
b = aSeg.b;
|
||||||
|
m_index = aSeg.m_index;
|
||||||
|
m_is_local = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
SEG& operator=( const SEG& aSeg )
|
||||||
* Function LineProject()
|
{
|
||||||
*
|
a = aSeg.a;
|
||||||
* Computes the perpendicular projection point of aP on a line passing through
|
b = aSeg.b;
|
||||||
* ends of the segment.
|
m_a = aSeg.m_a;
|
||||||
* @param aP point to project
|
m_b = aSeg.m_b;
|
||||||
* @return projected point
|
m_index = aSeg.m_index;
|
||||||
*/
|
m_is_local = aSeg.m_is_local;
|
||||||
VECTOR2I LineProject( const VECTOR2I& aP ) const;
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Side()
|
* Function LineProject()
|
||||||
*
|
*
|
||||||
* Determines on which side of directed line passing via segment ends point aP lies.
|
* Computes the perpendicular projection point of aP on a line passing through
|
||||||
* @param aP point to determine the orientation wrs to self
|
* ends of the segment.
|
||||||
* @return: < 0: left, 0 : on the line, > 0 : right
|
* @param aP point to project
|
||||||
*/
|
* @return projected point
|
||||||
int Side( const VECTOR2I& aP ) const
|
*/
|
||||||
{
|
VECTOR2I LineProject( const VECTOR2I& aP ) const;
|
||||||
const ecoord det = ( b - a ).Cross( aP - a );
|
|
||||||
|
|
||||||
return det < 0 ? -1 : ( det > 0 ? 1 : 0 );
|
/**
|
||||||
}
|
* Function Side()
|
||||||
|
*
|
||||||
|
* Determines on which side of directed line passing via segment ends point aP lies.
|
||||||
|
* @param aP point to determine the orientation wrs to self
|
||||||
|
* @return: < 0: left, 0 : on the line, > 0 : right
|
||||||
|
*/
|
||||||
|
int Side( const VECTOR2I& aP ) const
|
||||||
|
{
|
||||||
|
const ecoord det = ( b - a ).Cross( aP - a );
|
||||||
|
|
||||||
/**
|
return det < 0 ? -1 : ( det > 0 ? 1 : 0 );
|
||||||
* Function LineDistance()
|
}
|
||||||
*
|
|
||||||
* Returns the closest Euclidean distance between point aP and the line defined by
|
|
||||||
* the ends of segment (this).
|
|
||||||
* @param aDetermineSide: when true, the sign of the returned value indicates
|
|
||||||
* the side of the line at which we are (negative = left)
|
|
||||||
* @return the distance
|
|
||||||
*/
|
|
||||||
int LineDistance( const VECTOR2I& aP, bool aDetermineSide = false ) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function NearestPoint()
|
* Function LineDistance()
|
||||||
*
|
*
|
||||||
* Computes a point on the segment (this) that is closest to point aP.
|
* Returns the closest Euclidean distance between point aP and the line defined by
|
||||||
* @return: nearest point
|
* the ends of segment (this).
|
||||||
*/
|
* @param aDetermineSide: when true, the sign of the returned value indicates
|
||||||
const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
|
* the side of the line at which we are (negative = left)
|
||||||
|
* @return the distance
|
||||||
|
*/
|
||||||
|
int LineDistance( const VECTOR2I& aP, bool aDetermineSide = false ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Intersect()
|
* Function NearestPoint()
|
||||||
*
|
*
|
||||||
* Computes intersection point of segment (this) with segment aSeg.
|
* Computes a point on the segment (this) that is closest to point aP.
|
||||||
* @param aSeg: segment to intersect with
|
* @return: nearest point
|
||||||
* @param aIgnoreEndpoints: don't treat corner cases (i.e. end of one segment touching the other)
|
*/
|
||||||
* as intersections.
|
const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
|
||||||
* @param aLines: treat segments as infinite lines
|
|
||||||
* @return intersection point, if exists
|
|
||||||
*/
|
|
||||||
OPT_VECTOR2I Intersect( const SEG& aSeg, bool aIgnoreEndpoints = false, bool aLines = false ) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function IntersectLines()
|
* Function Intersect()
|
||||||
*
|
*
|
||||||
* Computes the intersection point of lines passing through ends of (this) and aSeg
|
* Computes intersection point of segment (this) with segment aSeg.
|
||||||
* @param aSeg segment defining the line to intersect with
|
* @param aSeg: segment to intersect with
|
||||||
* @return intersection point, if exists
|
* @param aIgnoreEndpoints: don't treat corner cases (i.e. end of one segment touching the other)
|
||||||
*/
|
* as intersections.
|
||||||
OPT_VECTOR2I IntersectLines( const SEG& aSeg ) const
|
* @param aLines: treat segments as infinite lines
|
||||||
{
|
* @return intersection point, if exists
|
||||||
return Intersect( aSeg, false, true );
|
*/
|
||||||
}
|
OPT_VECTOR2I Intersect( const SEG& aSeg, bool aIgnoreEndpoints = false, bool aLines = false ) const;
|
||||||
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance ) const;
|
/**
|
||||||
|
* Function IntersectLines()
|
||||||
|
*
|
||||||
|
* Computes the intersection point of lines passing through ends of (this) and aSeg
|
||||||
|
* @param aSeg segment defining the line to intersect with
|
||||||
|
* @return intersection point, if exists
|
||||||
|
*/
|
||||||
|
OPT_VECTOR2I IntersectLines( const SEG& aSeg ) const
|
||||||
|
{
|
||||||
|
return Intersect( aSeg, false, true );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
bool Collide( const SEG& aSeg, int aClearance ) const;
|
||||||
* Function Distance()
|
|
||||||
*
|
|
||||||
* Computes minimum Euclidean distance to segment aSeg.
|
|
||||||
* @param aSeg other segment
|
|
||||||
* @return minimum distance
|
|
||||||
*/
|
|
||||||
|
|
||||||
ecoord SquaredDistance( const SEG& aSeg ) const;
|
|
||||||
|
|
||||||
int Distance( const SEG& aSeg ) const
|
|
||||||
{
|
|
||||||
return sqrt( SquaredDistance( aSeg ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Distance()
|
|
||||||
*
|
|
||||||
* Computes minimum Euclidean distance to point aP.
|
|
||||||
* @param aP the point
|
|
||||||
* @return minimum distance
|
|
||||||
*/
|
|
||||||
ecoord SquaredDistance( const VECTOR2I& aP ) const
|
|
||||||
{
|
|
||||||
return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm();
|
|
||||||
}
|
|
||||||
|
|
||||||
int Distance( const VECTOR2I& aP ) const
|
/**
|
||||||
{
|
* Function Distance()
|
||||||
return sqrt( SquaredDistance( aP ) );
|
*
|
||||||
}
|
* Computes minimum Euclidean distance to segment aSeg.
|
||||||
|
* @param aSeg other segment
|
||||||
|
* @return minimum distance
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
ecoord SquaredDistance( const SEG& aSeg ) const;
|
||||||
* Function Collinear()
|
|
||||||
*
|
|
||||||
* Checks if segment aSeg lies on the same line as (this).
|
|
||||||
* @param aSeg the segment to chech colinearity with
|
|
||||||
* @return true, when segments are collinear.
|
|
||||||
*/
|
|
||||||
bool Collinear( const SEG& aSeg ) const
|
|
||||||
{
|
|
||||||
ecoord qa1 = a.y - b.y;
|
|
||||||
ecoord qb1 = b.x - a.x;
|
|
||||||
ecoord qc1 = -qa1 * a.x - qb1 * a.y;
|
|
||||||
ecoord qa2 = aSeg.a.y - aSeg.b.y;
|
|
||||||
ecoord qb2 = aSeg.b.x - aSeg.a.x;
|
|
||||||
ecoord qc2 = -qa2 * aSeg.a.x - qb2 * aSeg.a.y;
|
|
||||||
|
|
||||||
return ( qa1 == qa2 ) && ( qb1 == qb2 ) && ( qc1 == qc2 );
|
int Distance( const SEG& aSeg ) const
|
||||||
}
|
{
|
||||||
|
return sqrt( SquaredDistance( aSeg ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Length()
|
* Function Distance()
|
||||||
*
|
*
|
||||||
* Returns the length (this)
|
* Computes minimum Euclidean distance to point aP.
|
||||||
* @return length
|
* @param aP the point
|
||||||
*/
|
* @return minimum distance
|
||||||
int Length() const
|
*/
|
||||||
{
|
ecoord SquaredDistance( const VECTOR2I& aP ) const
|
||||||
return ( a - b ).EuclideanNorm();
|
{
|
||||||
}
|
return ( NearestPoint( aP ) - aP ).SquaredEuclideanNorm();
|
||||||
|
}
|
||||||
ecoord SquaredLength() const
|
|
||||||
{
|
|
||||||
return ( a - b ).SquaredEuclideanNorm();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
int Distance( const VECTOR2I& aP ) const
|
||||||
* Function Index()
|
{
|
||||||
*
|
return sqrt( SquaredDistance( aP ) );
|
||||||
* Return the index of this segment in its parent shape (applicable only to non-local segments)
|
}
|
||||||
* @return index value
|
|
||||||
*/
|
|
||||||
int Index() const
|
|
||||||
{
|
|
||||||
return m_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Contains( const VECTOR2I& aP ) const;
|
/**
|
||||||
|
* Function Collinear()
|
||||||
|
*
|
||||||
|
* Checks if segment aSeg lies on the same line as (this).
|
||||||
|
* @param aSeg the segment to chech colinearity with
|
||||||
|
* @return true, when segments are collinear.
|
||||||
|
*/
|
||||||
|
bool Collinear( const SEG& aSeg ) const
|
||||||
|
{
|
||||||
|
ecoord qa1 = a.y - b.y;
|
||||||
|
ecoord qb1 = b.x - a.x;
|
||||||
|
ecoord qc1 = -qa1 * a.x - qb1 * a.y;
|
||||||
|
ecoord qa2 = aSeg.a.y - aSeg.b.y;
|
||||||
|
ecoord qb2 = aSeg.b.x - aSeg.a.x;
|
||||||
|
ecoord qc2 = -qa2 * aSeg.a.x - qb2 * aSeg.a.y;
|
||||||
|
|
||||||
bool PointCloserThan( const VECTOR2I& aP, int aDist ) const;
|
return ( qa1 == qa2 ) && ( qb1 == qb2 ) && ( qc1 == qc2 );
|
||||||
|
}
|
||||||
|
|
||||||
// friend std::ostream& operator<<( std::ostream& stream, const SEG& aSeg );
|
/**
|
||||||
private:
|
* Function Length()
|
||||||
bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const;
|
*
|
||||||
|
* Returns the length (this)
|
||||||
///> locally stored start/end coordinates (used when m_is_local == true)
|
* @return length
|
||||||
VECTOR2I m_a, m_b;
|
*/
|
||||||
|
int Length() const
|
||||||
|
{
|
||||||
|
return ( a - b ).EuclideanNorm();
|
||||||
|
}
|
||||||
|
|
||||||
///> index withing the parent shape (used when m_is_local == false)
|
ecoord SquaredLength() const
|
||||||
int m_index;
|
{
|
||||||
|
return ( a - b ).SquaredEuclideanNorm();
|
||||||
|
}
|
||||||
|
|
||||||
///> locality flag
|
/**
|
||||||
bool m_is_local;
|
* Function Index()
|
||||||
|
*
|
||||||
|
* Return the index of this segment in its parent shape (applicable only to non-local segments)
|
||||||
|
* @return index value
|
||||||
|
*/
|
||||||
|
int Index() const
|
||||||
|
{
|
||||||
|
return m_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Contains( const VECTOR2I& aP ) const;
|
||||||
|
|
||||||
|
bool PointCloserThan( const VECTOR2I& aP, int aDist ) const;
|
||||||
|
|
||||||
|
// friend std::ostream& operator<<( std::ostream& stream, const SEG& aSeg );
|
||||||
|
private:
|
||||||
|
bool ccw( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I &aC ) const;
|
||||||
|
|
||||||
|
///> locally stored start/end coordinates (used when m_is_local == true)
|
||||||
|
VECTOR2I m_a, m_b;
|
||||||
|
|
||||||
|
///> index withing the parent shape (used when m_is_local == false)
|
||||||
|
int m_index;
|
||||||
|
|
||||||
|
///> locality flag
|
||||||
|
bool m_is_local;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const
|
inline VECTOR2I SEG::LineProject( const VECTOR2I& aP ) const
|
||||||
{
|
{
|
||||||
// fixme: numerical errors for large integers
|
// fixme: numerical errors for large integers
|
||||||
assert( false );
|
assert( false );
|
||||||
return VECTOR2I( 0, 0 );
|
return VECTOR2I( 0, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
|
inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
|
||||||
{
|
{
|
||||||
ecoord p = a.y - b.y;
|
ecoord p = a.y - b.y;
|
||||||
ecoord q = b.x - a.x;
|
ecoord q = b.x - a.x;
|
||||||
ecoord r = -p * a.x - q * a.y;
|
ecoord r = -p * a.x - q * a.y;
|
||||||
|
|
||||||
ecoord dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q );
|
ecoord dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q );
|
||||||
|
|
||||||
|
@ -321,14 +321,14 @@ inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const
|
||||||
|
|
||||||
if( l_squared == 0 )
|
if( l_squared == 0 )
|
||||||
return a;
|
return a;
|
||||||
|
|
||||||
ecoord t = d.Dot( aP - a );
|
ecoord t = d.Dot( aP - a );
|
||||||
|
|
||||||
if( t < 0 )
|
if( t < 0 )
|
||||||
return a;
|
return a;
|
||||||
else if( t > l_squared )
|
else if( t > l_squared )
|
||||||
return b;
|
return b;
|
||||||
|
|
||||||
int xp = rescale( t, (ecoord)d.x, l_squared );
|
int xp = rescale( t, (ecoord)d.x, l_squared );
|
||||||
int yp = rescale( t, (ecoord)d.y, l_squared );
|
int yp = rescale( t, (ecoord)d.y, l_squared );
|
||||||
|
|
||||||
|
@ -338,7 +338,7 @@ inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const
|
||||||
inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg )
|
inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg )
|
||||||
{
|
{
|
||||||
if( aSeg.m_is_local )
|
if( aSeg.m_is_local )
|
||||||
aStream << "[ local " << aSeg.a << " - " << aSeg.b << " ]";
|
aStream << "[ local " << aSeg.a << " - " << aSeg.b << " ]";
|
||||||
|
|
||||||
return aStream;
|
return aStream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,109 +36,109 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum ShapeType {
|
enum ShapeType {
|
||||||
SH_RECT = 0, ///> axis-aligned rectangle
|
SH_RECT = 0, ///> axis-aligned rectangle
|
||||||
SH_SEGMENT, ///> line segment
|
SH_SEGMENT, ///> line segment
|
||||||
SH_LINE_CHAIN, ///> line chain (polyline)
|
SH_LINE_CHAIN, ///> line chain (polyline)
|
||||||
SH_CIRCLE ///> circle
|
SH_CIRCLE ///> circle
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class SHAPE
|
* Class SHAPE
|
||||||
*
|
*
|
||||||
* Represents an abstract shape on 2D plane.
|
* Represents an abstract shape on 2D plane.
|
||||||
*/
|
*/
|
||||||
class SHAPE {
|
class SHAPE {
|
||||||
protected:
|
protected:
|
||||||
typedef VECTOR2I::extended_type ecoord;
|
typedef VECTOR2I::extended_type ecoord;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* Creates an empty shape of type aType
|
* Creates an empty shape of type aType
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SHAPE ( ShapeType aType ) : m_type( aType ) { };
|
SHAPE ( ShapeType aType ) : m_type( aType ) { };
|
||||||
|
|
||||||
// Destructor
|
|
||||||
virtual ~SHAPE() {};
|
|
||||||
|
|
||||||
/**
|
// Destructor
|
||||||
* Function Type()
|
virtual ~SHAPE() {};
|
||||||
*
|
|
||||||
* Returns the type of the shape.
|
|
||||||
* @retval the type
|
|
||||||
*/
|
|
||||||
ShapeType Type() const { return m_type; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Clone()
|
* Function Type()
|
||||||
*
|
*
|
||||||
* Returns a dynamically allocated copy of the shape
|
* Returns the type of the shape.
|
||||||
* @retval copy of the shape
|
* @retval the type
|
||||||
*/
|
*/
|
||||||
virtual SHAPE* Clone() const {
|
ShapeType Type() const { return m_type; }
|
||||||
assert( false );
|
|
||||||
return NULL;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Collide()
|
* Function Clone()
|
||||||
*
|
*
|
||||||
* Checks if the boundary of shape (this) lies closer to the point aP than aClearance, indicating
|
* Returns a dynamically allocated copy of the shape
|
||||||
* a collision.
|
* @retval copy of the shape
|
||||||
* @return true, if there is a collision.
|
*/
|
||||||
*/
|
virtual SHAPE* Clone() const {
|
||||||
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const
|
assert( false );
|
||||||
{
|
return NULL;
|
||||||
return Collide( SEG( aP, aP ), aClearance );
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Collide()
|
|
||||||
*
|
|
||||||
* Checks if the boundary of shape (this) lies closer to the shape aShape than aClearance, indicating
|
|
||||||
* a collision.
|
|
||||||
* @param aShape shape to check collision against
|
|
||||||
* @param aClearance minimum clearance
|
|
||||||
* @param aMTV minimum translation vector
|
|
||||||
* @return true, if there is a collision.
|
|
||||||
*/
|
|
||||||
virtual bool Collide( const SHAPE* aShape, int aClerance, VECTOR2I& aMTV ) const;
|
|
||||||
virtual bool Collide( const SHAPE* aShape, int aClerance = 0 ) const;
|
|
||||||
/**
|
|
||||||
* Function Collide()
|
|
||||||
*
|
|
||||||
* Checks if the boundary of shape (this) lies closer to the segment aSeg than aClearance, indicating
|
|
||||||
* a collision.
|
|
||||||
* @return true, if there is a collision.
|
|
||||||
*/
|
|
||||||
virtual bool Collide( const SEG& aSeg, int aClearance = 0 ) const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Collide()
|
|
||||||
*
|
|
||||||
* Computes a bounding box of the shape, with a margin of aClearance
|
|
||||||
* a collision.
|
|
||||||
* @aClearance how much the bounding box is expanded wrs to the minimum enclosing rectangle for the shape.
|
|
||||||
* @return the bounding box.
|
|
||||||
*/
|
|
||||||
virtual const BOX2I BBox( int aClearance = 0 ) const = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Centre()
|
* Function Collide()
|
||||||
*
|
*
|
||||||
* Computes a center-of-mass of the shape
|
* Checks if the boundary of shape (this) lies closer to the point aP than aClearance, indicating
|
||||||
* @return the center-of-mass point
|
* a collision.
|
||||||
*/
|
* @return true, if there is a collision.
|
||||||
virtual VECTOR2I Centre() const
|
*/
|
||||||
{
|
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const
|
||||||
return BBox( 0 ).Centre(); // if nothing better is available....
|
{
|
||||||
}
|
return Collide( SEG( aP, aP ), aClearance );
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
/**
|
||||||
///> type of our shape
|
* Function Collide()
|
||||||
ShapeType m_type;
|
*
|
||||||
|
* Checks if the boundary of shape (this) lies closer to the shape aShape than aClearance, indicating
|
||||||
|
* a collision.
|
||||||
|
* @param aShape shape to check collision against
|
||||||
|
* @param aClearance minimum clearance
|
||||||
|
* @param aMTV minimum translation vector
|
||||||
|
* @return true, if there is a collision.
|
||||||
|
*/
|
||||||
|
virtual bool Collide( const SHAPE* aShape, int aClerance, VECTOR2I& aMTV ) const;
|
||||||
|
virtual bool Collide( const SHAPE* aShape, int aClerance = 0 ) const;
|
||||||
|
/**
|
||||||
|
* Function Collide()
|
||||||
|
*
|
||||||
|
* Checks if the boundary of shape (this) lies closer to the segment aSeg than aClearance, indicating
|
||||||
|
* a collision.
|
||||||
|
* @return true, if there is a collision.
|
||||||
|
*/
|
||||||
|
virtual bool Collide( const SEG& aSeg, int aClearance = 0 ) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Collide()
|
||||||
|
*
|
||||||
|
* Computes a bounding box of the shape, with a margin of aClearance
|
||||||
|
* a collision.
|
||||||
|
* @aClearance how much the bounding box is expanded wrs to the minimum enclosing rectangle for the shape.
|
||||||
|
* @return the bounding box.
|
||||||
|
*/
|
||||||
|
virtual const BOX2I BBox( int aClearance = 0 ) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Centre()
|
||||||
|
*
|
||||||
|
* Computes a center-of-mass of the shape
|
||||||
|
* @return the center-of-mass point
|
||||||
|
*/
|
||||||
|
virtual VECTOR2I Centre() const
|
||||||
|
{
|
||||||
|
return BBox( 0 ).Centre(); // if nothing better is available....
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
///> type of our shape
|
||||||
|
ShapeType m_type;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -30,48 +30,48 @@
|
||||||
class SHAPE_CIRCLE : public SHAPE {
|
class SHAPE_CIRCLE : public SHAPE {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SHAPE_CIRCLE():
|
SHAPE_CIRCLE():
|
||||||
SHAPE( SH_CIRCLE ), m_radius( 0 ) {};
|
SHAPE( SH_CIRCLE ), m_radius( 0 ) {};
|
||||||
|
|
||||||
SHAPE_CIRCLE( const VECTOR2I& aCenter, int aRadius ):
|
|
||||||
SHAPE( SH_CIRCLE ), m_radius( aRadius ), m_center( aCenter ) {};
|
|
||||||
|
|
||||||
~SHAPE_CIRCLE() {};
|
SHAPE_CIRCLE( const VECTOR2I& aCenter, int aRadius ):
|
||||||
|
SHAPE( SH_CIRCLE ), m_radius( aRadius ), m_center( aCenter ) {};
|
||||||
|
|
||||||
const BOX2I BBox( int aClearance = 0 ) const
|
~SHAPE_CIRCLE() {};
|
||||||
{
|
|
||||||
const VECTOR2I rc( m_radius + aClearance, m_radius + aClearance );
|
|
||||||
return BOX2I( m_center - rc, rc * 2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
|
const BOX2I BBox( int aClearance = 0 ) const
|
||||||
{
|
{
|
||||||
int rc = aClearance + m_radius;
|
const VECTOR2I rc( m_radius + aClearance, m_radius + aClearance );
|
||||||
return aSeg.Distance( m_center ) <= rc;
|
return BOX2I( m_center - rc, rc * 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRadius( int aRadius )
|
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
|
||||||
{
|
{
|
||||||
m_radius = aRadius;
|
int rc = aClearance + m_radius;
|
||||||
}
|
return aSeg.Distance( m_center ) <= rc;
|
||||||
|
}
|
||||||
|
|
||||||
void SetCenter( const VECTOR2I& aCenter )
|
void SetRadius( int aRadius )
|
||||||
{
|
{
|
||||||
m_center = aCenter;
|
m_radius = aRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetRadius() const
|
void SetCenter( const VECTOR2I& aCenter )
|
||||||
{
|
{
|
||||||
return m_radius;
|
m_center = aCenter;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VECTOR2I GetCenter() const
|
int GetRadius() const
|
||||||
{
|
{
|
||||||
return m_center;
|
return m_radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VECTOR2I GetCenter() const
|
||||||
|
{
|
||||||
|
return m_center;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
int m_radius;
|
int m_radius;
|
||||||
VECTOR2I m_center;
|
VECTOR2I m_center;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -276,11 +276,11 @@ class SHAPE_INDEX
|
||||||
{
|
{
|
||||||
BOX2I box = aShape->BBox();
|
BOX2I box = aShape->BBox();
|
||||||
box.Inflate( aMinDistance );
|
box.Inflate( aMinDistance );
|
||||||
|
|
||||||
int min[2] = { box.GetX(), box.GetY() };
|
|
||||||
int max[2] = { box.GetRight(), box.GetBottom() };
|
|
||||||
|
|
||||||
return this->m_tree->Search( min, max, aVisitor );
|
int min[2] = { box.GetX(), box.GetY() };
|
||||||
|
int max[2] = { box.GetRight(), box.GetBottom() };
|
||||||
|
|
||||||
|
return this->m_tree->Search( min, max, aVisitor );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -29,205 +29,205 @@
|
||||||
|
|
||||||
template <class T> const SHAPE* defaultShapeFunctor( const T aItem )
|
template <class T> const SHAPE* defaultShapeFunctor( const T aItem )
|
||||||
{
|
{
|
||||||
return aItem->GetShape();
|
return aItem->GetShape();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, const SHAPE* (ShapeFunctor)(const T) = defaultShapeFunctor<T> >
|
template <class T, const SHAPE* (ShapeFunctor)(const T) = defaultShapeFunctor<T> >
|
||||||
|
|
||||||
class SHAPE_INDEX_LIST {
|
class SHAPE_INDEX_LIST {
|
||||||
|
|
||||||
struct ShapeEntry {
|
|
||||||
ShapeEntry( T aParent )
|
|
||||||
{
|
|
||||||
shape = ShapeFunctor( aParent );
|
|
||||||
bbox = shape->BBox( 0 );
|
|
||||||
parent = aParent;
|
|
||||||
}
|
|
||||||
|
|
||||||
~ShapeEntry()
|
struct ShapeEntry {
|
||||||
{
|
ShapeEntry( T aParent )
|
||||||
}
|
{
|
||||||
|
shape = ShapeFunctor( aParent );
|
||||||
|
bbox = shape->BBox( 0 );
|
||||||
|
parent = aParent;
|
||||||
|
}
|
||||||
|
|
||||||
T parent;
|
~ShapeEntry()
|
||||||
const SHAPE* shape;
|
{
|
||||||
BOX2I bbox;
|
}
|
||||||
};
|
|
||||||
|
T parent;
|
||||||
|
const SHAPE* shape;
|
||||||
|
BOX2I bbox;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<ShapeEntry> ShapeVec;
|
||||||
|
typedef typename std::vector<ShapeEntry>::iterator ShapeVecIter;
|
||||||
|
|
||||||
typedef std::vector<ShapeEntry> ShapeVec;
|
|
||||||
typedef typename std::vector<ShapeEntry>::iterator ShapeVecIter;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// "Normal" iterator interface, for STL algorithms.
|
// "Normal" iterator interface, for STL algorithms.
|
||||||
class iterator {
|
class iterator {
|
||||||
public:
|
public:
|
||||||
iterator() {};
|
iterator() {};
|
||||||
|
|
||||||
iterator( ShapeVecIter aCurrent )
|
iterator( ShapeVecIter aCurrent )
|
||||||
: m_current( aCurrent ) {};
|
: m_current( aCurrent ) {};
|
||||||
|
|
||||||
iterator( const iterator &aB ) :
|
iterator( const iterator &aB ) :
|
||||||
m_current( aB.m_current ) {};
|
m_current( aB.m_current ) {};
|
||||||
|
|
||||||
T operator*() const
|
T operator*() const
|
||||||
{
|
{
|
||||||
return (*m_current).parent;
|
return (*m_current).parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void operator++()
|
void operator++()
|
||||||
{
|
{
|
||||||
++m_current;
|
++m_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator& operator++( int aDummy )
|
iterator& operator++( int aDummy )
|
||||||
{
|
{
|
||||||
++m_current;
|
++m_current;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==( const iterator& aRhs ) const
|
bool operator==( const iterator& aRhs ) const
|
||||||
{
|
{
|
||||||
return m_current == aRhs.m_current;
|
return m_current == aRhs.m_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator!=( const iterator& aRhs ) const
|
bool operator!=( const iterator& aRhs ) const
|
||||||
{
|
{
|
||||||
return m_current != aRhs.m_current;
|
return m_current != aRhs.m_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
const iterator& operator=( const iterator& aRhs )
|
const iterator& operator=( const iterator& aRhs )
|
||||||
{
|
{
|
||||||
m_current = aRhs.m_current;
|
m_current = aRhs.m_current;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShapeVecIter m_current;
|
ShapeVecIter m_current;
|
||||||
};
|
};
|
||||||
|
|
||||||
// "Query" iterator, for iterating over a set of spatially matching shapes.
|
// "Query" iterator, for iterating over a set of spatially matching shapes.
|
||||||
class query_iterator {
|
class query_iterator {
|
||||||
public:
|
public:
|
||||||
query_iterator()
|
query_iterator()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
query_iterator( ShapeVecIter aCurrent, ShapeVecIter aEnd, SHAPE* aShape,
|
query_iterator( ShapeVecIter aCurrent, ShapeVecIter aEnd, SHAPE* aShape,
|
||||||
int aMinDistance, bool aExact ) :
|
int aMinDistance, bool aExact ) :
|
||||||
m_end( aEnd ),
|
m_end( aEnd ),
|
||||||
m_current( aCurrent ),
|
m_current( aCurrent ),
|
||||||
m_shape( aShape ),
|
m_shape( aShape ),
|
||||||
m_minDistance( aMinDistance ),
|
m_minDistance( aMinDistance ),
|
||||||
m_exact( aExact )
|
m_exact( aExact )
|
||||||
{
|
{
|
||||||
if( aShape )
|
if( aShape )
|
||||||
{
|
{
|
||||||
m_refBBox = aShape->BBox();
|
m_refBBox = aShape->BBox();
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
query_iterator( const query_iterator &aB ) :
|
query_iterator( const query_iterator &aB ) :
|
||||||
m_end( aB.m_end ),
|
m_end( aB.m_end ),
|
||||||
m_current( aB.m_current ),
|
m_current( aB.m_current ),
|
||||||
m_shape( aB.m_shape ),
|
m_shape( aB.m_shape ),
|
||||||
m_minDistance( aB.m_minDistance ),
|
m_minDistance( aB.m_minDistance ),
|
||||||
m_exact( aB.m_exact ),
|
m_exact( aB.m_exact ),
|
||||||
m_refBBox( aB.m_refBBox )
|
m_refBBox( aB.m_refBBox )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
T operator*() const
|
|
||||||
{
|
|
||||||
return (*m_current).parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
query_iterator& operator++()
|
T operator*() const
|
||||||
{
|
{
|
||||||
++m_current;
|
return (*m_current).parent;
|
||||||
next();
|
}
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
query_iterator& operator++( int aDummy )
|
query_iterator& operator++()
|
||||||
{
|
{
|
||||||
++m_current;
|
++m_current;
|
||||||
next();
|
next();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==( const query_iterator& aRhs ) const
|
query_iterator& operator++( int aDummy )
|
||||||
{
|
{
|
||||||
return m_current == aRhs.m_current;
|
++m_current;
|
||||||
}
|
next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator!=( const query_iterator& aRhs ) const
|
bool operator==( const query_iterator& aRhs ) const
|
||||||
{
|
{
|
||||||
return m_current != aRhs.m_current;
|
return m_current == aRhs.m_current;
|
||||||
}
|
}
|
||||||
|
|
||||||
const query_iterator& operator=( const query_iterator& aRhs )
|
bool operator!=( const query_iterator& aRhs ) const
|
||||||
{
|
{
|
||||||
m_end = aRhs.m_end;
|
return m_current != aRhs.m_current;
|
||||||
m_current = aRhs.m_current;
|
}
|
||||||
m_shape = aRhs.m_shape;
|
|
||||||
m_minDistance = aRhs.m_minDistance;
|
|
||||||
m_exact = aRhs.m_exact;
|
|
||||||
m_refBBox = aRhs.m_refBBox;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
const query_iterator& operator=( const query_iterator& aRhs )
|
||||||
void next()
|
{
|
||||||
{
|
m_end = aRhs.m_end;
|
||||||
while( m_current != m_end )
|
m_current = aRhs.m_current;
|
||||||
{
|
m_shape = aRhs.m_shape;
|
||||||
if( m_refBBox.Distance( m_current->bbox ) <= m_minDistance )
|
m_minDistance = aRhs.m_minDistance;
|
||||||
{
|
m_exact = aRhs.m_exact;
|
||||||
if( !m_exact || m_current->shape->Collide( m_shape, m_minDistance ) )
|
m_refBBox = aRhs.m_refBBox;
|
||||||
return;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
++m_current;
|
private:
|
||||||
}
|
void next()
|
||||||
}
|
{
|
||||||
|
while( m_current != m_end )
|
||||||
|
{
|
||||||
|
if( m_refBBox.Distance( m_current->bbox ) <= m_minDistance )
|
||||||
|
{
|
||||||
|
if( !m_exact || m_current->shape->Collide( m_shape, m_minDistance ) )
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ShapeVecIter m_end;
|
++m_current;
|
||||||
ShapeVecIter m_current;
|
}
|
||||||
BOX2I m_refBBox;
|
}
|
||||||
bool m_exact;
|
|
||||||
SHAPE *m_shape;
|
|
||||||
int m_minDistance;
|
|
||||||
};
|
|
||||||
|
|
||||||
void Add( T aItem )
|
ShapeVecIter m_end;
|
||||||
{
|
ShapeVecIter m_current;
|
||||||
ShapeEntry s( aItem );
|
BOX2I m_refBBox;
|
||||||
|
bool m_exact;
|
||||||
|
SHAPE *m_shape;
|
||||||
|
int m_minDistance;
|
||||||
|
};
|
||||||
|
|
||||||
m_shapes.push_back(s);
|
void Add( T aItem )
|
||||||
}
|
{
|
||||||
|
ShapeEntry s( aItem );
|
||||||
void Remove( const T aItem )
|
|
||||||
{
|
|
||||||
ShapeVecIter i;
|
|
||||||
|
|
||||||
for( i = m_shapes.begin(); i != m_shapes.end(); ++i )
|
|
||||||
{
|
|
||||||
if( i->parent == aItem )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( i == m_shapes.end() )
|
m_shapes.push_back(s);
|
||||||
return;
|
}
|
||||||
|
|
||||||
m_shapes.erase( i );
|
void Remove( const T aItem )
|
||||||
}
|
{
|
||||||
|
ShapeVecIter i;
|
||||||
|
|
||||||
int Size() const
|
for( i = m_shapes.begin(); i != m_shapes.end(); ++i )
|
||||||
{
|
{
|
||||||
return m_shapes.size();
|
if( i->parent == aItem )
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
template<class Visitor>
|
if( i == m_shapes.end() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_shapes.erase( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
int Size() const
|
||||||
|
{
|
||||||
|
return m_shapes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Visitor>
|
||||||
int Query( const SHAPE *aShape, int aMinDistance, Visitor &aV, bool aExact = true ) //const
|
int Query( const SHAPE *aShape, int aMinDistance, Visitor &aV, bool aExact = true ) //const
|
||||||
{
|
{
|
||||||
ShapeVecIter i;
|
ShapeVecIter i;
|
||||||
|
@ -251,33 +251,33 @@ public:
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
m_shapes.clear();
|
m_shapes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
query_iterator qbegin( SHAPE* aShape, int aMinDistance, bool aExact )
|
|
||||||
{
|
|
||||||
return query_iterator( m_shapes.begin(), m_shapes.end(), aShape, aMinDistance, aExact );
|
|
||||||
}
|
|
||||||
|
|
||||||
const query_iterator qend()
|
query_iterator qbegin( SHAPE* aShape, int aMinDistance, bool aExact )
|
||||||
{
|
{
|
||||||
return query_iterator( m_shapes.end(), m_shapes.end(), NULL, 0, false );
|
return query_iterator( m_shapes.begin(), m_shapes.end(), aShape, aMinDistance, aExact );
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator begin()
|
const query_iterator qend()
|
||||||
{
|
{
|
||||||
return iterator( m_shapes.begin() );
|
return query_iterator( m_shapes.end(), m_shapes.end(), NULL, 0, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end()
|
iterator begin()
|
||||||
{
|
{
|
||||||
return iterator( m_shapes.end() );
|
return iterator( m_shapes.begin() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
iterator end()
|
||||||
|
{
|
||||||
|
return iterator( m_shapes.end() );
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ShapeVec m_shapes;
|
ShapeVec m_shapes;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,504 +38,504 @@
|
||||||
* Class SHAPE_LINE_CHAIN
|
* Class SHAPE_LINE_CHAIN
|
||||||
*
|
*
|
||||||
* Represents a polyline (an zero-thickness chain of connected line segments).
|
* Represents a polyline (an zero-thickness chain of connected line segments).
|
||||||
* I purposedly didn't name it "polyline" to avoid confusion with the existing CPolyLine class in pcbnew.
|
* I purposedly didn't name it "polyline" to avoid confusion with the existing CPolyLine class in pcbnew.
|
||||||
*
|
*
|
||||||
* SHAPE_LINE_CHAIN class shall not be used for polygons!
|
* SHAPE_LINE_CHAIN class shall not be used for polygons!
|
||||||
*/
|
*/
|
||||||
class SHAPE_LINE_CHAIN : public SHAPE {
|
class SHAPE_LINE_CHAIN : public SHAPE {
|
||||||
private:
|
private:
|
||||||
typedef std::vector<VECTOR2I>::iterator point_iter;
|
typedef std::vector<VECTOR2I>::iterator point_iter;
|
||||||
typedef std::vector<VECTOR2I>::const_iterator point_citer;
|
typedef std::vector<VECTOR2I>::const_iterator point_citer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Struct Intersection
|
* Struct Intersection
|
||||||
*
|
*
|
||||||
* Represents an intersection between two line segments
|
* Represents an intersection between two line segments
|
||||||
*/
|
*/
|
||||||
struct Intersection
|
struct Intersection
|
||||||
{
|
{
|
||||||
/// segment belonging from the (this) argument of Intersect()
|
/// segment belonging from the (this) argument of Intersect()
|
||||||
SEG our;
|
SEG our;
|
||||||
/// segment belonging from the aOther argument of Intersect()
|
/// segment belonging from the aOther argument of Intersect()
|
||||||
SEG their;
|
SEG their;
|
||||||
/// point of intersection between our and their.
|
/// point of intersection between our and their.
|
||||||
VECTOR2I p;
|
VECTOR2I p;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Intersection> Intersections;
|
typedef std::vector<Intersection> Intersections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* Initializes an empty line chain.
|
* Initializes an empty line chain.
|
||||||
*/
|
*/
|
||||||
SHAPE_LINE_CHAIN():
|
SHAPE_LINE_CHAIN():
|
||||||
SHAPE( SH_LINE_CHAIN ), m_closed( false ) {};
|
SHAPE( SH_LINE_CHAIN ), m_closed( false ) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy Constructor
|
* Copy Constructor
|
||||||
*/
|
*/
|
||||||
SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape ) :
|
SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape ) :
|
||||||
SHAPE( SH_LINE_CHAIN ), m_points( aShape.m_points ), m_closed( aShape.m_closed ) {};
|
SHAPE( SH_LINE_CHAIN ), m_points( aShape.m_points ), m_closed( aShape.m_closed ) {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* Initializes a 2-point line chain (a single segment)
|
* Initializes a 2-point line chain (a single segment)
|
||||||
*/
|
*/
|
||||||
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB ) :
|
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB ) :
|
||||||
SHAPE( SH_LINE_CHAIN ),
|
SHAPE( SH_LINE_CHAIN ),
|
||||||
m_closed( false )
|
m_closed( false )
|
||||||
{
|
{
|
||||||
m_points.resize( 2 );
|
m_points.resize( 2 );
|
||||||
m_points[0] = aA;
|
m_points[0] = aA;
|
||||||
m_points[1] = aB;
|
m_points[1] = aB;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ):
|
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ):
|
||||||
SHAPE( SH_LINE_CHAIN ),
|
SHAPE( SH_LINE_CHAIN ),
|
||||||
m_closed( false )
|
m_closed( false )
|
||||||
{
|
{
|
||||||
m_points.resize( 3 );
|
m_points.resize( 3 );
|
||||||
m_points[0] = aA;
|
m_points[0] = aA;
|
||||||
m_points[1] = aB;
|
m_points[1] = aB;
|
||||||
m_points[2] = aC;
|
m_points[2] = aC;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHAPE_LINE_CHAIN(const VECTOR2I* aV, int aCount ) :
|
SHAPE_LINE_CHAIN(const VECTOR2I* aV, int aCount ) :
|
||||||
SHAPE( SH_LINE_CHAIN ),
|
SHAPE( SH_LINE_CHAIN ),
|
||||||
m_closed( false )
|
m_closed( false )
|
||||||
{
|
{
|
||||||
m_points.resize( aCount );
|
m_points.resize( aCount );
|
||||||
|
|
||||||
for( int i = 0; i < aCount; i++ )
|
for( int i = 0; i < aCount; i++ )
|
||||||
m_points[i] = *aV++;
|
m_points[i] = *aV++;
|
||||||
}
|
}
|
||||||
|
|
||||||
~SHAPE_LINE_CHAIN() {};
|
~SHAPE_LINE_CHAIN() {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Clear()
|
* Function Clear()
|
||||||
* Removes all points from the line chain.
|
* Removes all points from the line chain.
|
||||||
*/
|
*/
|
||||||
void Clear()
|
void Clear()
|
||||||
{
|
{
|
||||||
m_points.clear();
|
m_points.clear();
|
||||||
m_closed = false;
|
m_closed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function SetClosed()
|
* Function SetClosed()
|
||||||
*
|
*
|
||||||
* Marks the line chain as closed (i.e. with a segment connecting the last point with the first point).
|
* Marks the line chain as closed (i.e. with a segment connecting the last point with the first point).
|
||||||
* @param aClosed: whether the line chain is to be closed or not.
|
* @param aClosed: whether the line chain is to be closed or not.
|
||||||
*/
|
*/
|
||||||
void SetClosed( bool aClosed )
|
void SetClosed( bool aClosed )
|
||||||
{
|
{
|
||||||
m_closed = aClosed;
|
m_closed = aClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function IsClosed()
|
* Function IsClosed()
|
||||||
*
|
*
|
||||||
* @return aClosed: true, when our line is closed.
|
* @return aClosed: true, when our line is closed.
|
||||||
*/
|
*/
|
||||||
bool IsClosed() const
|
bool IsClosed() const
|
||||||
{
|
{
|
||||||
return m_closed;
|
return m_closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function SegmentCount()
|
* Function SegmentCount()
|
||||||
*
|
*
|
||||||
* Returns number of segments in this line chain.
|
* Returns number of segments in this line chain.
|
||||||
* @return number of segments
|
* @return number of segments
|
||||||
*/
|
*/
|
||||||
int SegmentCount() const
|
int SegmentCount() const
|
||||||
{
|
{
|
||||||
int c = m_points.size() - 1;
|
int c = m_points.size() - 1;
|
||||||
if( m_closed )
|
if( m_closed )
|
||||||
c++;
|
c++;
|
||||||
|
|
||||||
return std::max( 0, c );
|
return std::max( 0, c );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function PointCount()
|
* Function PointCount()
|
||||||
*
|
*
|
||||||
* Returns the number of points (vertices) in this line chain
|
* Returns the number of points (vertices) in this line chain
|
||||||
* @return number of points
|
* @return number of points
|
||||||
*/
|
*/
|
||||||
int PointCount() const
|
int PointCount() const
|
||||||
{
|
{
|
||||||
return m_points.size();
|
return m_points.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Segment()
|
* Function Segment()
|
||||||
*
|
*
|
||||||
* Returns a segment referencing to the segment (index) in the line chain.
|
* Returns a segment referencing to the segment (index) in the line chain.
|
||||||
* Modifying ends of the returned segment will modify corresponding points in the line chain.
|
* Modifying ends of the returned segment will modify corresponding points in the line chain.
|
||||||
* @param aIndex: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means
|
* @param aIndex: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means
|
||||||
* the last segment in the line chain)
|
* the last segment in the line chain)
|
||||||
* @return SEG referenced to given segment in the line chain
|
* @return SEG referenced to given segment in the line chain
|
||||||
*/
|
*/
|
||||||
SEG Segment( int aIndex )
|
SEG Segment( int aIndex )
|
||||||
{
|
{
|
||||||
if( aIndex < 0 )
|
if( aIndex < 0 )
|
||||||
aIndex += SegmentCount();
|
aIndex += SegmentCount();
|
||||||
|
|
||||||
if( aIndex == ( m_points.size() - 1 ) && m_closed )
|
if( aIndex == ( m_points.size() - 1 ) && m_closed )
|
||||||
return SEG( m_points[aIndex], m_points[0], aIndex );
|
return SEG( m_points[aIndex], m_points[0], aIndex );
|
||||||
else
|
else
|
||||||
return SEG( m_points[aIndex], m_points[aIndex + 1], aIndex );
|
return SEG( m_points[aIndex], m_points[aIndex + 1], aIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function CSegment()
|
* Function CSegment()
|
||||||
*
|
*
|
||||||
* Returns a read-only segment referencing to the segment (index) in the line chain.
|
* Returns a read-only segment referencing to the segment (index) in the line chain.
|
||||||
* @param aIndex: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means
|
* @param aIndex: index of the segment in the line chain. Negative values are counted from the end (i.e. -1 means
|
||||||
* the last segment in the line chain)
|
* the last segment in the line chain)
|
||||||
* @return SEG referenced to given segment in the line chain
|
* @return SEG referenced to given segment in the line chain
|
||||||
*/
|
*/
|
||||||
const SEG CSegment( int aIndex ) const
|
const SEG CSegment( int aIndex ) const
|
||||||
{
|
{
|
||||||
if( aIndex < 0 )
|
if( aIndex < 0 )
|
||||||
aIndex += SegmentCount();
|
aIndex += SegmentCount();
|
||||||
|
|
||||||
if( aIndex == ( m_points.size() - 1 ) && m_closed )
|
if( aIndex == ( m_points.size() - 1 ) && m_closed )
|
||||||
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
|
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
|
||||||
const_cast<VECTOR2I&>( m_points[0] ), aIndex );
|
const_cast<VECTOR2I&>( m_points[0] ), aIndex );
|
||||||
else
|
else
|
||||||
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
|
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
|
||||||
const_cast<VECTOR2I&>( m_points[aIndex + 1] ), aIndex );
|
const_cast<VECTOR2I&>( m_points[aIndex + 1] ), aIndex );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Point()
|
* Function Point()
|
||||||
*
|
*
|
||||||
* Returns a reference to a given point in the line chain.
|
* Returns a reference to a given point in the line chain.
|
||||||
* @param aIndex index of the point
|
* @param aIndex index of the point
|
||||||
* @return reference to the point
|
* @return reference to the point
|
||||||
*/
|
*/
|
||||||
VECTOR2I& Point( int aIndex )
|
VECTOR2I& Point( int aIndex )
|
||||||
{
|
{
|
||||||
if( aIndex < 0 )
|
if( aIndex < 0 )
|
||||||
aIndex += PointCount();
|
aIndex += PointCount();
|
||||||
|
|
||||||
return m_points[aIndex];
|
return m_points[aIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function CPoint()
|
* Function CPoint()
|
||||||
*
|
*
|
||||||
* Returns a const reference to a given point in the line chain.
|
* Returns a const reference to a given point in the line chain.
|
||||||
* @param aIndex index of the point
|
* @param aIndex index of the point
|
||||||
* @return const reference to the point
|
* @return const reference to the point
|
||||||
*/
|
*/
|
||||||
const VECTOR2I& CPoint( int aIndex ) const
|
const VECTOR2I& CPoint( int aIndex ) const
|
||||||
{
|
{
|
||||||
if( aIndex < 0 )
|
if( aIndex < 0 )
|
||||||
aIndex += PointCount();
|
aIndex += PointCount();
|
||||||
|
|
||||||
return m_points[aIndex];
|
return m_points[aIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @copydoc SHAPE::BBox()
|
/// @copydoc SHAPE::BBox()
|
||||||
const BOX2I BBox( int aClearance = 0 ) const
|
const BOX2I BBox( int aClearance = 0 ) const
|
||||||
{
|
{
|
||||||
BOX2I bbox;
|
BOX2I bbox;
|
||||||
bbox.Compute( m_points );
|
bbox.Compute( m_points );
|
||||||
|
|
||||||
return bbox;
|
return bbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Collide()
|
* Function Collide()
|
||||||
*
|
*
|
||||||
* Checks if point aP lies closer to us than aClearance.
|
* Checks if point aP lies closer to us than aClearance.
|
||||||
* @param aP the point to check for collisions with
|
* @param aP the point to check for collisions with
|
||||||
* @param aClearance minimum distance that does not qualify as a collision.
|
* @param aClearance minimum distance that does not qualify as a collision.
|
||||||
* @return true, when a collision has been found
|
* @return true, when a collision has been found
|
||||||
*/
|
*/
|
||||||
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const;
|
bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Collide()
|
|
||||||
*
|
|
||||||
* Checks if box aBox lies closer to us than aClearance.
|
|
||||||
* @param aP the box to check for collisions with
|
|
||||||
* @param aClearance minimum distance that does not qualify as a collision.
|
|
||||||
* @return true, when a collision has been found
|
|
||||||
*/
|
|
||||||
bool Collide( const BOX2I& aBox, int aClearance = 0 ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Collide()
|
|
||||||
*
|
|
||||||
* Checks if segment aSeg lies closer to us than aClearance.
|
|
||||||
* @param aSeg the segment to check for collisions with
|
|
||||||
* @param aClearance minimum distance that does not qualify as a collision.
|
|
||||||
* @return true, when a collision has been found
|
|
||||||
*/
|
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Distance()
|
|
||||||
*
|
|
||||||
* Computes the minimum distance between the line chain and a point aP.
|
|
||||||
* @param aP the point
|
|
||||||
* @return minimum distance.
|
|
||||||
*/
|
|
||||||
int Distance( const VECTOR2I& aP ) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Reverse()
|
* Function Collide()
|
||||||
*
|
*
|
||||||
* Reverses point order in the line chain.
|
* Checks if box aBox lies closer to us than aClearance.
|
||||||
* @return line chain with reversed point order (original A-B-C-D: returned D-C-B-A)
|
* @param aP the box to check for collisions with
|
||||||
*/
|
* @param aClearance minimum distance that does not qualify as a collision.
|
||||||
const SHAPE_LINE_CHAIN Reverse() const;
|
* @return true, when a collision has been found
|
||||||
|
*/
|
||||||
|
bool Collide( const BOX2I& aBox, int aClearance = 0 ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Length()
|
* Function Collide()
|
||||||
*
|
*
|
||||||
* Returns length of the line chain in Euclidean metric.
|
* Checks if segment aSeg lies closer to us than aClearance.
|
||||||
* @return length of the line chain
|
* @param aSeg the segment to check for collisions with
|
||||||
*/
|
* @param aClearance minimum distance that does not qualify as a collision.
|
||||||
int Length() const;
|
* @return true, when a collision has been found
|
||||||
|
*/
|
||||||
/**
|
bool Collide( const SEG& aSeg, int aClearance = 0 ) const;
|
||||||
* Function Append()
|
|
||||||
*
|
|
||||||
* Appends a new point at the end of the line chain.
|
|
||||||
* @param aX is X coordinate of the new point
|
|
||||||
* @param aY is Y coordinate of the new point
|
|
||||||
*/
|
|
||||||
void Append( int aX, int aY )
|
|
||||||
{
|
|
||||||
VECTOR2I v( aX, aY );
|
|
||||||
Append( v );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Append()
|
* Function Distance()
|
||||||
*
|
*
|
||||||
* Appends a new point at the end of the line chain.
|
* Computes the minimum distance between the line chain and a point aP.
|
||||||
* @param aP the new point
|
* @param aP the point
|
||||||
*/
|
* @return minimum distance.
|
||||||
void Append( const VECTOR2I& aP )
|
*/
|
||||||
{
|
int Distance( const VECTOR2I& aP ) const;
|
||||||
if( m_points.size() == 0 )
|
|
||||||
m_bbox = BOX2I( aP, VECTOR2I( 0, 0 ) );
|
|
||||||
|
|
||||||
if( m_points.size() == 0 || CPoint( -1 ) != aP )
|
|
||||||
{
|
|
||||||
m_points.push_back( aP );
|
|
||||||
m_bbox.Merge( aP );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Append()
|
* Function Reverse()
|
||||||
*
|
*
|
||||||
* Appends another line chain at the end.
|
* Reverses point order in the line chain.
|
||||||
* @param aOtherLine the line chain to be appended.
|
* @return line chain with reversed point order (original A-B-C-D: returned D-C-B-A)
|
||||||
*/
|
*/
|
||||||
void Append( const SHAPE_LINE_CHAIN& aOtherLine )
|
const SHAPE_LINE_CHAIN Reverse() const;
|
||||||
{
|
|
||||||
if( aOtherLine.PointCount() == 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
else if( PointCount() == 0 || aOtherLine.CPoint( 0 ) != CPoint( -1 ) )
|
/**
|
||||||
{
|
* Function Length()
|
||||||
const VECTOR2I p = aOtherLine.CPoint( 0 );
|
*
|
||||||
m_points.push_back( p );
|
* Returns length of the line chain in Euclidean metric.
|
||||||
m_bbox.Merge( p );
|
* @return length of the line chain
|
||||||
}
|
*/
|
||||||
|
int Length() const;
|
||||||
|
|
||||||
for( int i = 1; i < aOtherLine.PointCount(); i++ )
|
/**
|
||||||
{
|
* Function Append()
|
||||||
const VECTOR2I p = aOtherLine.CPoint( i );
|
*
|
||||||
m_points.push_back( p );
|
* Appends a new point at the end of the line chain.
|
||||||
m_bbox.Merge( p );
|
* @param aX is X coordinate of the new point
|
||||||
}
|
* @param aY is Y coordinate of the new point
|
||||||
}
|
*/
|
||||||
|
void Append( int aX, int aY )
|
||||||
|
{
|
||||||
|
VECTOR2I v( aX, aY );
|
||||||
|
Append( v );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Replace()
|
* Function Append()
|
||||||
*
|
*
|
||||||
* Replaces points with indices in range [start_index, end_index] with a single
|
* Appends a new point at the end of the line chain.
|
||||||
* point aP.
|
* @param aP the new point
|
||||||
* @param aStartIndex start of the point range to be replaced (inclusive)
|
*/
|
||||||
* @param aEndIndex end of the point range to be replaced (inclusive)
|
void Append( const VECTOR2I& aP )
|
||||||
* @param aP replacement point
|
{
|
||||||
*/
|
if( m_points.size() == 0 )
|
||||||
void Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP );
|
m_bbox = BOX2I( aP, VECTOR2I( 0, 0 ) );
|
||||||
|
|
||||||
/**
|
if( m_points.size() == 0 || CPoint( -1 ) != aP )
|
||||||
* Function Replace()
|
{
|
||||||
*
|
m_points.push_back( aP );
|
||||||
* Replaces points with indices in range [start_index, end_index] with the points from
|
m_bbox.Merge( aP );
|
||||||
* line chain aLine.
|
}
|
||||||
* @param aStartIndex start of the point range to be replaced (inclusive)
|
}
|
||||||
* @param aEndIndex end of the point range to be replaced (inclusive)
|
|
||||||
* @param aLine replacement line chain.
|
|
||||||
*/
|
|
||||||
void Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Remove()
|
* Function Append()
|
||||||
*
|
*
|
||||||
* Removes the range of points [start_index, end_index] from the line chain.
|
* Appends another line chain at the end.
|
||||||
* @param aStartIndex start of the point range to be replaced (inclusive)
|
* @param aOtherLine the line chain to be appended.
|
||||||
* @param aEndIndex end of the point range to be replaced (inclusive)
|
*/
|
||||||
*/
|
void Append( const SHAPE_LINE_CHAIN& aOtherLine )
|
||||||
void Remove( int aStartIndex, int aEndIndex );
|
{
|
||||||
|
if( aOtherLine.PointCount() == 0 )
|
||||||
/**
|
return;
|
||||||
* Function Split()
|
|
||||||
*
|
|
||||||
* Inserts the point aP belonging to one of the our segments, splitting the adjacent
|
|
||||||
* segment in two.
|
|
||||||
* @param aP the point to be inserted
|
|
||||||
* @return index of the newly inserted point (or a negative value if aP does not lie on our line)
|
|
||||||
*/
|
|
||||||
int Split( const VECTOR2I& aP );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Find()
|
|
||||||
*
|
|
||||||
* Searches for point aP.
|
|
||||||
* @param aP the point to be looked for
|
|
||||||
* @return index of the correspoinding point in the line chain or negative when not found.
|
|
||||||
*/
|
|
||||||
int Find ( const VECTOR2I& aP ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Slice()
|
|
||||||
*
|
|
||||||
* Returns a subset of this line chain containing the [start_index, end_index] range of points.
|
|
||||||
* @param aStartIndex start of the point range to be returned (inclusive)
|
|
||||||
* @param aEndIndex end of the point range to be returned (inclusive)
|
|
||||||
* @return cut line chain.
|
|
||||||
*/
|
|
||||||
const SHAPE_LINE_CHAIN Slice( int aStartIndex, int aEndIndex = -1) const;
|
|
||||||
|
|
||||||
struct compareOriginDistance
|
else if( PointCount() == 0 || aOtherLine.CPoint( 0 ) != CPoint( -1 ) )
|
||||||
{
|
{
|
||||||
compareOriginDistance( VECTOR2I& aOrigin ):
|
const VECTOR2I p = aOtherLine.CPoint( 0 );
|
||||||
m_origin( aOrigin ) {};
|
m_points.push_back( p );
|
||||||
|
m_bbox.Merge( p );
|
||||||
|
}
|
||||||
|
|
||||||
bool operator()( const Intersection& aA, const Intersection& aB )
|
for( int i = 1; i < aOtherLine.PointCount(); i++ )
|
||||||
{
|
{
|
||||||
return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
|
const VECTOR2I p = aOtherLine.CPoint( i );
|
||||||
}
|
m_points.push_back( p );
|
||||||
|
m_bbox.Merge( p );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VECTOR2I m_origin;
|
/**
|
||||||
};
|
* Function Replace()
|
||||||
|
*
|
||||||
|
* Replaces points with indices in range [start_index, end_index] with a single
|
||||||
|
* point aP.
|
||||||
|
* @param aStartIndex start of the point range to be replaced (inclusive)
|
||||||
|
* @param aEndIndex end of the point range to be replaced (inclusive)
|
||||||
|
* @param aP replacement point
|
||||||
|
*/
|
||||||
|
void Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Intersect()
|
* Function Replace()
|
||||||
*
|
*
|
||||||
* Finds all intersection points between our line chain and the segment aSeg.
|
* Replaces points with indices in range [start_index, end_index] with the points from
|
||||||
* @param aSeg the segment chain to find intersections with
|
* line chain aLine.
|
||||||
* @param aIp reference to a vector to store found intersections. Intersection points
|
* @param aStartIndex start of the point range to be replaced (inclusive)
|
||||||
* are sorted with increasing distances from point aSeg.a.
|
* @param aEndIndex end of the point range to be replaced (inclusive)
|
||||||
* @return number of intersections found
|
* @param aLine replacement line chain.
|
||||||
*/
|
*/
|
||||||
int Intersect ( const SEG& aSeg, Intersections& aIp ) const;
|
void Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine );
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Intersect()
|
|
||||||
*
|
|
||||||
* Finds all intersection points between our line chain and the line chain aChain.
|
|
||||||
* @param aChain the line chain to find intersections with
|
|
||||||
* @param aIp reference to a vector to store found intersections. Intersection points
|
|
||||||
* are sorted with increasing path lengths from the starting point of aChain.
|
|
||||||
* @return number of intersections found
|
|
||||||
*/
|
|
||||||
int Intersect( const SHAPE_LINE_CHAIN& aChain, Intersections& aIp ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function PathLength()
|
|
||||||
*
|
|
||||||
* Computes the walk path length from the beginning of the line chain and
|
|
||||||
* the point aP belonging to our line.
|
|
||||||
* @return: path length in Euclidean metric or negative if aP does not belong to the line chain.
|
|
||||||
*/
|
|
||||||
int PathLength( const VECTOR2I& aP ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function PointInside()
|
|
||||||
*
|
|
||||||
* Checks if point aP lies inside a convex polygon defined by the line chain. For closed
|
|
||||||
* shapes only.
|
|
||||||
* @param aP point to check
|
|
||||||
* @return true if the point is inside the shape (edge is not treated as being inside).
|
|
||||||
*/
|
|
||||||
bool PointInside( const VECTOR2I& aP ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function PointOnEdge()
|
|
||||||
*
|
|
||||||
* Checks if point aP lies on an edge or vertex of the line chain.
|
|
||||||
* @param aP point to check
|
|
||||||
* @return true if the point lies on the edge.
|
|
||||||
*/
|
|
||||||
bool PointOnEdge( const VECTOR2I& aP ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function SelfIntersecting()
|
|
||||||
*
|
|
||||||
* Checks if the line chain is self-intersecting.
|
|
||||||
* @return (optional) first found self-intersection point.
|
|
||||||
*/
|
|
||||||
const boost::optional<Intersection> SelfIntersecting() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function Simplify()
|
|
||||||
*
|
|
||||||
* Simplifies the line chain by removing colinear adjacent segments and duplicate vertices.
|
|
||||||
* @return reference to self.
|
|
||||||
*/
|
|
||||||
SHAPE_LINE_CHAIN& Simplify();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function NearestPoint()
|
|
||||||
*
|
|
||||||
* Finds a point on the line chain that is closest to point aP.
|
|
||||||
* @return the nearest point.
|
|
||||||
*/
|
|
||||||
const VECTOR2I NearestPoint( const VECTOR2I& aP ) const;
|
|
||||||
|
|
||||||
/// @copydoc SHAPE::Format()
|
|
||||||
const std::string Format() const;
|
|
||||||
|
|
||||||
bool operator!=( const SHAPE_LINE_CHAIN& aRhs ) const
|
/**
|
||||||
{
|
* Function Remove()
|
||||||
if( PointCount() != aRhs.PointCount() )
|
*
|
||||||
return true;
|
* Removes the range of points [start_index, end_index] from the line chain.
|
||||||
|
* @param aStartIndex start of the point range to be replaced (inclusive)
|
||||||
|
* @param aEndIndex end of the point range to be replaced (inclusive)
|
||||||
|
*/
|
||||||
|
void Remove( int aStartIndex, int aEndIndex );
|
||||||
|
|
||||||
for( int i = 0; i < PointCount(); i++ )
|
/**
|
||||||
{
|
* Function Split()
|
||||||
if( CPoint( i ) != aRhs.CPoint( i ) )
|
*
|
||||||
return true;
|
* Inserts the point aP belonging to one of the our segments, splitting the adjacent
|
||||||
}
|
* segment in two.
|
||||||
|
* @param aP the point to be inserted
|
||||||
|
* @return index of the newly inserted point (or a negative value if aP does not lie on our line)
|
||||||
|
*/
|
||||||
|
int Split( const VECTOR2I& aP );
|
||||||
|
|
||||||
return false;
|
/**
|
||||||
}
|
* Function Find()
|
||||||
|
*
|
||||||
|
* Searches for point aP.
|
||||||
|
* @param aP the point to be looked for
|
||||||
|
* @return index of the correspoinding point in the line chain or negative when not found.
|
||||||
|
*/
|
||||||
|
int Find ( const VECTOR2I& aP ) const;
|
||||||
|
|
||||||
private:
|
/**
|
||||||
/// array of vertices
|
* Function Slice()
|
||||||
std::vector<VECTOR2I> m_points;
|
*
|
||||||
|
* Returns a subset of this line chain containing the [start_index, end_index] range of points.
|
||||||
|
* @param aStartIndex start of the point range to be returned (inclusive)
|
||||||
|
* @param aEndIndex end of the point range to be returned (inclusive)
|
||||||
|
* @return cut line chain.
|
||||||
|
*/
|
||||||
|
const SHAPE_LINE_CHAIN Slice( int aStartIndex, int aEndIndex = -1) const;
|
||||||
|
|
||||||
/// is the line chain closed?
|
struct compareOriginDistance
|
||||||
bool m_closed;
|
{
|
||||||
|
compareOriginDistance( VECTOR2I& aOrigin ):
|
||||||
|
m_origin( aOrigin ) {};
|
||||||
|
|
||||||
/// cached bounding box
|
bool operator()( const Intersection& aA, const Intersection& aB )
|
||||||
BOX2I m_bbox;
|
{
|
||||||
|
return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
|
||||||
|
}
|
||||||
|
|
||||||
|
VECTOR2I m_origin;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Intersect()
|
||||||
|
*
|
||||||
|
* Finds all intersection points between our line chain and the segment aSeg.
|
||||||
|
* @param aSeg the segment chain to find intersections with
|
||||||
|
* @param aIp reference to a vector to store found intersections. Intersection points
|
||||||
|
* are sorted with increasing distances from point aSeg.a.
|
||||||
|
* @return number of intersections found
|
||||||
|
*/
|
||||||
|
int Intersect ( const SEG& aSeg, Intersections& aIp ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Intersect()
|
||||||
|
*
|
||||||
|
* Finds all intersection points between our line chain and the line chain aChain.
|
||||||
|
* @param aChain the line chain to find intersections with
|
||||||
|
* @param aIp reference to a vector to store found intersections. Intersection points
|
||||||
|
* are sorted with increasing path lengths from the starting point of aChain.
|
||||||
|
* @return number of intersections found
|
||||||
|
*/
|
||||||
|
int Intersect( const SHAPE_LINE_CHAIN& aChain, Intersections& aIp ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function PathLength()
|
||||||
|
*
|
||||||
|
* Computes the walk path length from the beginning of the line chain and
|
||||||
|
* the point aP belonging to our line.
|
||||||
|
* @return: path length in Euclidean metric or negative if aP does not belong to the line chain.
|
||||||
|
*/
|
||||||
|
int PathLength( const VECTOR2I& aP ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function PointInside()
|
||||||
|
*
|
||||||
|
* Checks if point aP lies inside a convex polygon defined by the line chain. For closed
|
||||||
|
* shapes only.
|
||||||
|
* @param aP point to check
|
||||||
|
* @return true if the point is inside the shape (edge is not treated as being inside).
|
||||||
|
*/
|
||||||
|
bool PointInside( const VECTOR2I& aP ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function PointOnEdge()
|
||||||
|
*
|
||||||
|
* Checks if point aP lies on an edge or vertex of the line chain.
|
||||||
|
* @param aP point to check
|
||||||
|
* @return true if the point lies on the edge.
|
||||||
|
*/
|
||||||
|
bool PointOnEdge( const VECTOR2I& aP ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function SelfIntersecting()
|
||||||
|
*
|
||||||
|
* Checks if the line chain is self-intersecting.
|
||||||
|
* @return (optional) first found self-intersection point.
|
||||||
|
*/
|
||||||
|
const boost::optional<Intersection> SelfIntersecting() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Simplify()
|
||||||
|
*
|
||||||
|
* Simplifies the line chain by removing colinear adjacent segments and duplicate vertices.
|
||||||
|
* @return reference to self.
|
||||||
|
*/
|
||||||
|
SHAPE_LINE_CHAIN& Simplify();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function NearestPoint()
|
||||||
|
*
|
||||||
|
* Finds a point on the line chain that is closest to point aP.
|
||||||
|
* @return the nearest point.
|
||||||
|
*/
|
||||||
|
const VECTOR2I NearestPoint( const VECTOR2I& aP ) const;
|
||||||
|
|
||||||
|
/// @copydoc SHAPE::Format()
|
||||||
|
const std::string Format() const;
|
||||||
|
|
||||||
|
bool operator!=( const SHAPE_LINE_CHAIN& aRhs ) const
|
||||||
|
{
|
||||||
|
if( PointCount() != aRhs.PointCount() )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for( int i = 0; i < PointCount(); i++ )
|
||||||
|
{
|
||||||
|
if( CPoint( i ) != aRhs.CPoint( i ) )
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// array of vertices
|
||||||
|
std::vector<VECTOR2I> m_points;
|
||||||
|
|
||||||
|
/// is the line chain closed?
|
||||||
|
bool m_closed;
|
||||||
|
|
||||||
|
/// cached bounding box
|
||||||
|
BOX2I m_bbox;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __SHAPE_LINE_CHAIN
|
#endif // __SHAPE_LINE_CHAIN
|
||||||
|
|
|
@ -31,114 +31,114 @@
|
||||||
#include <geometry/seg.h>
|
#include <geometry/seg.h>
|
||||||
|
|
||||||
class SHAPE_RECT : public SHAPE {
|
class SHAPE_RECT : public SHAPE {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* Creates an empty (0-sized) rectangle
|
* Creates an empty (0-sized) rectangle
|
||||||
*/
|
*/
|
||||||
SHAPE_RECT() :
|
SHAPE_RECT() :
|
||||||
SHAPE( SH_RECT ), m_w( 0 ), m_h( 0 ) {};
|
SHAPE( SH_RECT ), m_w( 0 ), m_h( 0 ) {};
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* Creates a rectangle defined by top-left corner (aX0, aY0), width aW and height aH.
|
|
||||||
*/
|
|
||||||
SHAPE_RECT( int aX0, int aY0, int aW, int aH ) :
|
|
||||||
SHAPE( SH_RECT ), m_p0( aX0, aY0 ), m_w( aW ), m_h( aH ) {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* Creates a rectangle defined by top-left corner aP0, width aW and height aH.
|
* Creates a rectangle defined by top-left corner (aX0, aY0), width aW and height aH.
|
||||||
*/
|
*/
|
||||||
SHAPE_RECT( const VECTOR2I &aP0, int aW, int aH ) :
|
SHAPE_RECT( int aX0, int aY0, int aW, int aH ) :
|
||||||
SHAPE( SH_RECT ), m_p0( aP0 ), m_w( aW ), m_h( aH ) {};
|
SHAPE( SH_RECT ), m_p0( aX0, aY0 ), m_w( aW ), m_h( aH ) {};
|
||||||
|
|
||||||
/// @copydoc SHAPE::BBox()
|
/**
|
||||||
const BOX2I BBox(int aClearance = 0) const
|
* Constructor
|
||||||
{
|
* Creates a rectangle defined by top-left corner aP0, width aW and height aH.
|
||||||
BOX2I bbox( VECTOR2I( m_p0.x - aClearance, m_p0.y - aClearance ),
|
*/
|
||||||
VECTOR2I( m_w + 2 * aClearance, m_h + 2 * aClearance ) );
|
SHAPE_RECT( const VECTOR2I &aP0, int aW, int aH ) :
|
||||||
//printf("bb : %s\n",bbox.Format().c_str());
|
SHAPE( SH_RECT ), m_p0( aP0 ), m_w( aW ), m_h( aH ) {};
|
||||||
return bbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/// @copydoc SHAPE::BBox()
|
||||||
* Function Diagonal()
|
const BOX2I BBox(int aClearance = 0) const
|
||||||
*
|
{
|
||||||
* Returns length of the diagonal of the rectangle
|
BOX2I bbox( VECTOR2I( m_p0.x - aClearance, m_p0.y - aClearance ),
|
||||||
* @return diagonal length
|
VECTOR2I( m_w + 2 * aClearance, m_h + 2 * aClearance ) );
|
||||||
*/
|
//printf("bb : %s\n",bbox.Format().c_str());
|
||||||
int Diagonal() const
|
return bbox;
|
||||||
{
|
}
|
||||||
return VECTOR2I( m_w, m_h ).EuclideanNorm();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @copydoc SHAPE::Collide()
|
/**
|
||||||
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
|
* Function Diagonal()
|
||||||
{
|
*
|
||||||
//VECTOR2I pmin = VECTOR2I(std::min(aSeg.a.x, aSeg.b.x), std::min(aSeg.a.y, aSeg.b.y));
|
* Returns length of the diagonal of the rectangle
|
||||||
//VECTOR2I pmax = VECTOR2I(std::max(aSeg.a.x, aSeg.b.x), std::max(aSeg.a.y, aSeg.b.y));
|
* @return diagonal length
|
||||||
//BOX2I r(pmin, VECTOR2I(pmax.x - pmin.x, pmax.y - pmin.y));
|
*/
|
||||||
|
int Diagonal() const
|
||||||
|
{
|
||||||
|
return VECTOR2I( m_w, m_h ).EuclideanNorm();
|
||||||
|
}
|
||||||
|
|
||||||
//if (BBox(0).SquaredDistance(r) > aClearance * aClearance)
|
/// @copydoc SHAPE::Collide()
|
||||||
// return false;
|
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
|
||||||
|
{
|
||||||
if( BBox( 0 ).Contains( aSeg.a ) || BBox( 0 ).Contains( aSeg.b ) )
|
//VECTOR2I pmin = VECTOR2I(std::min(aSeg.a.x, aSeg.b.x), std::min(aSeg.a.y, aSeg.b.y));
|
||||||
return true;
|
//VECTOR2I pmax = VECTOR2I(std::max(aSeg.a.x, aSeg.b.x), std::max(aSeg.a.y, aSeg.b.y));
|
||||||
|
//BOX2I r(pmin, VECTOR2I(pmax.x - pmin.x, pmax.y - pmin.y));
|
||||||
|
|
||||||
VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ),
|
//if (BBox(0).SquaredDistance(r) > aClearance * aClearance)
|
||||||
VECTOR2I( m_p0.x, m_p0.y + m_h ),
|
// return false;
|
||||||
VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ),
|
|
||||||
VECTOR2I( m_p0.x + m_w, m_p0.y ),
|
|
||||||
VECTOR2I( m_p0.x, m_p0.y ) };
|
|
||||||
|
|
||||||
for( int i = 0; i < 4; i++ )
|
if( BBox( 0 ).Contains( aSeg.a ) || BBox( 0 ).Contains( aSeg.b ) )
|
||||||
{
|
return true;
|
||||||
SEG s( vts[i], vts[i + 1], i );
|
|
||||||
if( s.Distance( aSeg ) <= aClearance )
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ),
|
||||||
* Function GetPosition()
|
VECTOR2I( m_p0.x, m_p0.y + m_h ),
|
||||||
*
|
VECTOR2I( m_p0.x + m_w, m_p0.y + m_h ),
|
||||||
* @return top-left corner of the rectangle
|
VECTOR2I( m_p0.x + m_w, m_p0.y ),
|
||||||
*/
|
VECTOR2I( m_p0.x, m_p0.y ) };
|
||||||
const VECTOR2I& GetPosition() const { return m_p0; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function GetSize()
|
|
||||||
*
|
|
||||||
* @return size of the rectangle
|
|
||||||
*/
|
|
||||||
const VECTOR2I GetSize() const { return VECTOR2I( m_w, m_h ); }
|
|
||||||
|
|
||||||
/**
|
for( int i = 0; i < 4; i++ )
|
||||||
* Function GetWidth()
|
{
|
||||||
*
|
SEG s( vts[i], vts[i + 1], i );
|
||||||
* @return width of the rectangle
|
if( s.Distance( aSeg ) <= aClearance )
|
||||||
*/
|
return true;
|
||||||
const int GetWidth() const { return m_w; }
|
}
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* Function GetHeight()
|
};
|
||||||
*
|
|
||||||
* @return height of the rectangle
|
|
||||||
*/
|
|
||||||
const int GetHeight() const { return m_h; }
|
|
||||||
|
|
||||||
private:
|
/**
|
||||||
///> Top-left corner
|
* Function GetPosition()
|
||||||
VECTOR2I m_p0;
|
*
|
||||||
|
* @return top-left corner of the rectangle
|
||||||
|
*/
|
||||||
|
const VECTOR2I& GetPosition() const { return m_p0; }
|
||||||
|
|
||||||
///> Width
|
/**
|
||||||
int m_w;
|
* Function GetSize()
|
||||||
|
*
|
||||||
|
* @return size of the rectangle
|
||||||
|
*/
|
||||||
|
const VECTOR2I GetSize() const { return VECTOR2I( m_w, m_h ); }
|
||||||
|
|
||||||
///> Height
|
/**
|
||||||
int m_h;
|
* Function GetWidth()
|
||||||
};
|
*
|
||||||
|
* @return width of the rectangle
|
||||||
|
*/
|
||||||
|
const int GetWidth() const { return m_w; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetHeight()
|
||||||
|
*
|
||||||
|
* @return height of the rectangle
|
||||||
|
*/
|
||||||
|
const int GetHeight() const { return m_h; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
///> Top-left corner
|
||||||
|
VECTOR2I m_p0;
|
||||||
|
|
||||||
|
///> Width
|
||||||
|
int m_w;
|
||||||
|
|
||||||
|
///> Height
|
||||||
|
int m_h;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // __SHAPE_RECT_H
|
#endif // __SHAPE_RECT_H
|
||||||
|
|
|
@ -66,7 +66,7 @@ public:
|
||||||
BOX2( const Vec& aPos, const Vec& aSize ) :
|
BOX2( const Vec& aPos, const Vec& aSize ) :
|
||||||
m_Pos( aPos ),
|
m_Pos( aPos ),
|
||||||
m_Size( aSize )
|
m_Size( aSize )
|
||||||
{
|
{
|
||||||
Normalize();
|
Normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +420,7 @@ public:
|
||||||
ecoord_type y2 = m_Pos.y + m_Size.y;
|
ecoord_type y2 = m_Pos.y + m_Size.y;
|
||||||
ecoord_type xdiff = std::max( aP.x < m_Pos.x ? m_Pos.x - aP.x : m_Pos.x - x2, (ecoord_type)0 );
|
ecoord_type xdiff = std::max( aP.x < m_Pos.x ? m_Pos.x - aP.x : m_Pos.x - x2, (ecoord_type)0 );
|
||||||
ecoord_type ydiff = std::max( aP.y < m_Pos.y ? m_Pos.y - aP.y : m_Pos.y - y2, (ecoord_type)0 );
|
ecoord_type ydiff = std::max( aP.y < m_Pos.y ? m_Pos.y - aP.y : m_Pos.y - y2, (ecoord_type)0 );
|
||||||
return xdiff * xdiff + ydiff * ydiff;
|
return xdiff * xdiff + ydiff * ydiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
ecoord_type Distance( const Vec& aP ) const
|
ecoord_type Distance( const Vec& aP ) const
|
||||||
|
|
|
@ -224,7 +224,7 @@ public:
|
||||||
|
|
||||||
/// Division with a factor
|
/// Division with a factor
|
||||||
VECTOR2<T> operator/( const T& aFactor ) const;
|
VECTOR2<T> operator/( const T& aFactor ) const;
|
||||||
|
|
||||||
/// Equality operator
|
/// Equality operator
|
||||||
const bool operator==( const VECTOR2<T>& aVector ) const;
|
const bool operator==( const VECTOR2<T>& aVector ) const;
|
||||||
|
|
||||||
|
|
|
@ -37,105 +37,105 @@ class TOOL_INTERACTIVE;
|
||||||
* Defines the structure of a context (usually right-click) popup menu
|
* Defines the structure of a context (usually right-click) popup menu
|
||||||
* for a given tool.
|
* for a given tool.
|
||||||
*/
|
*/
|
||||||
class CONTEXT_MENU
|
class CONTEXT_MENU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///> Default constructor
|
///> Default constructor
|
||||||
CONTEXT_MENU();
|
CONTEXT_MENU();
|
||||||
|
|
||||||
///> Copy constructor
|
///> Copy constructor
|
||||||
CONTEXT_MENU( const CONTEXT_MENU& aMenu );
|
CONTEXT_MENU( const CONTEXT_MENU& aMenu );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function SetTitle()
|
* Function SetTitle()
|
||||||
* Sets title for the context menu. The title is shown as a text label shown on the top of
|
* Sets title for the context menu. The title is shown as a text label shown on the top of
|
||||||
* the menu.
|
* the menu.
|
||||||
* @param aTitle is the new title.
|
* @param aTitle is the new title.
|
||||||
*/
|
*/
|
||||||
void SetTitle( const wxString& aTitle );
|
void SetTitle( const wxString& aTitle );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Add()
|
* Function Add()
|
||||||
* Adds an entry to the menu. After highlighting/selecting the entry, a TOOL_EVENT command is
|
* Adds an entry to the menu. After highlighting/selecting the entry, a TOOL_EVENT command is
|
||||||
* sent that contains ID of the entry.
|
* sent that contains ID of the entry.
|
||||||
* @param aLabel is the text label show in the menu.
|
* @param aLabel is the text label show in the menu.
|
||||||
* @param aId is the ID that is sent in the TOOL_EVENT. It should be unique for every entry.
|
* @param aId is the ID that is sent in the TOOL_EVENT. It should be unique for every entry.
|
||||||
*/
|
*/
|
||||||
void Add( const wxString& aLabel, int aId );
|
void Add( const wxString& aLabel, int aId );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Add()
|
* Function Add()
|
||||||
* Adds an entry to the menu, basing on the TOOL_ACTION object. After selecting the entry,
|
* Adds an entry to the menu, basing on the TOOL_ACTION object. After selecting the entry,
|
||||||
* a TOOL_EVENT command containing name of the action is sent.
|
* a TOOL_EVENT command containing name of the action is sent.
|
||||||
* @param aAction is the action to be added to menu entry.
|
* @param aAction is the action to be added to menu entry.
|
||||||
*/
|
*/
|
||||||
void Add( const TOOL_ACTION& aAction );
|
void Add( const TOOL_ACTION& aAction );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Clear()
|
* Function Clear()
|
||||||
* Removes all the entries from the menu (as well as its title). It leaves the menu in the
|
* Removes all the entries from the menu (as well as its title). It leaves the menu in the
|
||||||
* initial state.
|
* initial state.
|
||||||
*/
|
*/
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetMenu()
|
* Function GetMenu()
|
||||||
* Returns the instance of wxMenu object used to display the menu.
|
* Returns the instance of wxMenu object used to display the menu.
|
||||||
*/
|
*/
|
||||||
wxMenu* GetMenu() const
|
wxMenu* GetMenu() const
|
||||||
{
|
{
|
||||||
return const_cast<wxMenu*>( &m_menu );
|
return const_cast<wxMenu*>( &m_menu );
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///> Class CMEventHandler takes care of handling menu events. After reception of particular
|
///> Class CMEventHandler takes care of handling menu events. After reception of particular
|
||||||
///> events, it translates them to TOOL_EVENTs that may control tools.
|
///> events, it translates them to TOOL_EVENTs that may control tools.
|
||||||
class CMEventHandler : public wxEvtHandler
|
class CMEventHandler : public wxEvtHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
///> Default constructor
|
///> Default constructor
|
||||||
///> aMenu is the CONTEXT_MENU instance for which it handles events.
|
///> aMenu is the CONTEXT_MENU instance for which it handles events.
|
||||||
CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {};
|
CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {};
|
||||||
|
|
||||||
///> Handler for menu events.
|
///> Handler for menu events.
|
||||||
void onEvent( wxEvent& aEvent );
|
void onEvent( wxEvent& aEvent );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///> CONTEXT_MENU instance for which it handles events.
|
///> CONTEXT_MENU instance for which it handles events.
|
||||||
CONTEXT_MENU* m_menu;
|
CONTEXT_MENU* m_menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
friend class TOOL_INTERACTIVE;
|
|
||||||
|
|
||||||
/**
|
friend class TOOL_INTERACTIVE;
|
||||||
* Function setTool()
|
|
||||||
* Sets a tool that is the creator of the menu.
|
|
||||||
* @param aTool is the tool that created the menu.
|
|
||||||
*/
|
|
||||||
void setTool( TOOL_INTERACTIVE* aTool )
|
|
||||||
{
|
|
||||||
m_tool = aTool;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function getHotKeyDescription()
|
* Function setTool()
|
||||||
* Returns a hot key in the string format accepted by wxMenu.
|
* Sets a tool that is the creator of the menu.
|
||||||
* @param aAction is the action with hot key to be translated..
|
* @param aTool is the tool that created the menu.
|
||||||
* @return Hot key in the string format compatible with wxMenu.
|
*/
|
||||||
*/
|
void setTool( TOOL_INTERACTIVE* aTool )
|
||||||
std::string getHotKeyDescription( const TOOL_ACTION& aAction ) const;
|
{
|
||||||
|
m_tool = aTool;
|
||||||
|
}
|
||||||
|
|
||||||
///> Flag indicating that the menu title was set up.
|
/**
|
||||||
bool m_titleSet;
|
* Function getHotKeyDescription()
|
||||||
|
* Returns a hot key in the string format accepted by wxMenu.
|
||||||
|
* @param aAction is the action with hot key to be translated..
|
||||||
|
* @return Hot key in the string format compatible with wxMenu.
|
||||||
|
*/
|
||||||
|
std::string getHotKeyDescription( const TOOL_ACTION& aAction ) const;
|
||||||
|
|
||||||
///> Instance of wxMenu used for display of the context menu.
|
///> Flag indicating that the menu title was set up.
|
||||||
wxMenu m_menu;
|
bool m_titleSet;
|
||||||
|
|
||||||
///> Instance of menu event handler.
|
///> Instance of wxMenu used for display of the context menu.
|
||||||
CMEventHandler m_handler;
|
wxMenu m_menu;
|
||||||
|
|
||||||
///> Creator of the menu
|
///> Instance of menu event handler.
|
||||||
TOOL_INTERACTIVE* m_tool;
|
CMEventHandler m_handler;
|
||||||
|
|
||||||
|
///> Creator of the menu
|
||||||
|
TOOL_INTERACTIVE* m_tool;
|
||||||
|
|
||||||
/// Menu items with ID higher than that are considered TOOL_ACTIONs
|
/// Menu items with ID higher than that are considered TOOL_ACTIONs
|
||||||
static const int m_actionId = 10000;
|
static const int m_actionId = 10000;
|
||||||
|
|
|
@ -34,13 +34,13 @@
|
||||||
/**
|
/**
|
||||||
Class COROUNTINE.
|
Class COROUNTINE.
|
||||||
Implements a coroutine. Wikipedia has a good explanation:
|
Implements a coroutine. Wikipedia has a good explanation:
|
||||||
|
|
||||||
"Coroutines are computer program components that generalize subroutines to
|
"Coroutines are computer program components that generalize subroutines to
|
||||||
allow multiple entry points for suspending and resuming execution at certain locations.
|
allow multiple entry points for suspending and resuming execution at certain locations.
|
||||||
Coroutines are well-suited for implementing more familiar program components such as cooperative
|
Coroutines are well-suited for implementing more familiar program components such as cooperative
|
||||||
tasks, exceptions, event loop, iterators, infinite lists and pipes."
|
tasks, exceptions, event loop, iterators, infinite lists and pipes."
|
||||||
|
|
||||||
In other words, a coroutine can be considered a lightweight thread - which can be
|
In other words, a coroutine can be considered a lightweight thread - which can be
|
||||||
preempted only when it deliberately yields the control to the caller. This way,
|
preempted only when it deliberately yields the control to the caller. This way,
|
||||||
we avoid concurrency problems such as locking / race conditions.
|
we avoid concurrency problems such as locking / race conditions.
|
||||||
|
|
||||||
|
@ -56,82 +56,82 @@ template<class ReturnType, class ArgType>
|
||||||
class COROUTINE
|
class COROUTINE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
COROUTINE()
|
COROUTINE()
|
||||||
{
|
{
|
||||||
m_stackSize = c_defaultStackSize;
|
m_stackSize = c_defaultStackSize;
|
||||||
m_stack = NULL;
|
m_stack = NULL;
|
||||||
m_saved = NULL;
|
m_saved = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
* Creates a coroutine from a member method of an object
|
|
||||||
*/
|
|
||||||
template<class T>
|
|
||||||
COROUTINE( T* object, ReturnType (T::*ptr)( ArgType ) ) :
|
|
||||||
m_func( object, ptr ), m_saved( NULL ), m_stack( NULL ), m_stackSize( c_defaultStackSize )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* Creates a coroutine from a delegate object
|
* Creates a coroutine from a member method of an object
|
||||||
*/
|
*/
|
||||||
COROUTINE( DELEGATE<ReturnType, ArgType> aEntry ) :
|
template<class T>
|
||||||
|
COROUTINE( T* object, ReturnType (T::*ptr)( ArgType ) ) :
|
||||||
|
m_func( object, ptr ), m_saved( NULL ), m_stack( NULL ), m_stackSize( c_defaultStackSize )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* Creates a coroutine from a delegate object
|
||||||
|
*/
|
||||||
|
COROUTINE( DELEGATE<ReturnType, ArgType> aEntry ) :
|
||||||
m_func( aEntry ), m_saved( NULL ), m_stack( NULL ), m_stackSize( c_defaultStackSize )
|
m_func( aEntry ), m_saved( NULL ), m_stack( NULL ), m_stackSize( c_defaultStackSize )
|
||||||
{};
|
{};
|
||||||
|
|
||||||
~COROUTINE()
|
~COROUTINE()
|
||||||
{
|
{
|
||||||
if( m_saved )
|
if( m_saved )
|
||||||
delete m_saved;
|
delete m_saved;
|
||||||
if( m_stack )
|
if( m_stack )
|
||||||
free( m_stack );
|
free( m_stack );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Yield()
|
* Function Yield()
|
||||||
*
|
*
|
||||||
* Stops execution of the coroutine and returns control to the caller.
|
* Stops execution of the coroutine and returns control to the caller.
|
||||||
* After a yield, Call() or Resume() methods invoked by the caller will
|
* After a yield, Call() or Resume() methods invoked by the caller will
|
||||||
* immediately return true, indicating that we are not done yet, just asleep.
|
* immediately return true, indicating that we are not done yet, just asleep.
|
||||||
*/
|
*/
|
||||||
void Yield()
|
void Yield()
|
||||||
{
|
{
|
||||||
boost::context::jump_fcontext( m_self, m_saved, 0 );
|
boost::context::jump_fcontext( m_self, m_saved, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Yield()
|
* Function Yield()
|
||||||
*
|
*
|
||||||
* Yield with a value - passes a value of given type to the caller.
|
* Yield with a value - passes a value of given type to the caller.
|
||||||
* Useful for implementing generator objects.
|
* Useful for implementing generator objects.
|
||||||
*/
|
*/
|
||||||
void Yield( ReturnType& retVal )
|
void Yield( ReturnType& retVal )
|
||||||
{
|
{
|
||||||
m_retVal = retVal;
|
m_retVal = retVal;
|
||||||
boost::context::jump_fcontext( m_self, m_saved, 0 );
|
boost::context::jump_fcontext( m_self, m_saved, 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
<F11>* Function SetEntry()
|
<F11>* Function SetEntry()
|
||||||
*
|
*
|
||||||
* Defines the entry point for the coroutine, if not set in the constructor.
|
* Defines the entry point for the coroutine, if not set in the constructor.
|
||||||
*/
|
*/
|
||||||
void SetEntry( DELEGATE<ReturnType, ArgType> aEntry )
|
void SetEntry( DELEGATE<ReturnType, ArgType> aEntry )
|
||||||
{
|
{
|
||||||
m_func = aEntry;
|
m_func = aEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function Call()
|
/* Function Call()
|
||||||
*
|
*
|
||||||
* Starts execution of a coroutine, passing args as its arguments.
|
* Starts execution of a coroutine, passing args as its arguments.
|
||||||
* @return true, if the coroutine has yielded and false if it has finished its
|
* @return true, if the coroutine has yielded and false if it has finished its
|
||||||
* execution (returned).
|
* execution (returned).
|
||||||
*/
|
*/
|
||||||
bool Call( ArgType args )
|
bool Call( ArgType args )
|
||||||
{
|
{
|
||||||
// fixme: Clean up stack stuff. Add a guard
|
// fixme: Clean up stack stuff. Add a guard
|
||||||
m_stack = malloc( c_defaultStackSize );
|
m_stack = malloc( c_defaultStackSize );
|
||||||
|
|
||||||
// align to 16 bytes
|
// align to 16 bytes
|
||||||
|
@ -145,87 +145,87 @@ public:
|
||||||
// off we go!
|
// off we go!
|
||||||
boost::context::jump_fcontext( m_saved, m_self, reinterpret_cast<intptr_t>( this ) );
|
boost::context::jump_fcontext( m_saved, m_self, reinterpret_cast<intptr_t>( this ) );
|
||||||
return m_running;
|
return m_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Resume()
|
* Function Resume()
|
||||||
*
|
*
|
||||||
* Resumes execution of a previously yielded coroutine.
|
* Resumes execution of a previously yielded coroutine.
|
||||||
* @return true, if the coroutine has yielded again and false if it has finished its
|
* @return true, if the coroutine has yielded again and false if it has finished its
|
||||||
* execution (returned).
|
* execution (returned).
|
||||||
*/
|
*/
|
||||||
bool Resume()
|
bool Resume()
|
||||||
{
|
{
|
||||||
boost::context::jump_fcontext( m_saved, m_self, 0 );
|
boost::context::jump_fcontext( m_saved, m_self, 0 );
|
||||||
return m_running;
|
return m_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function ReturnValue()
|
* Function ReturnValue()
|
||||||
*
|
*
|
||||||
* Returns the yielded value (the argument Yield() was called with)
|
* Returns the yielded value (the argument Yield() was called with)
|
||||||
*/
|
*/
|
||||||
const ReturnType& ReturnValue() const
|
const ReturnType& ReturnValue() const
|
||||||
{
|
{
|
||||||
return m_retVal;
|
return m_retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Running()
|
* Function Running()
|
||||||
*
|
*
|
||||||
* @return true, if the coroutine is active
|
* @return true, if the coroutine is active
|
||||||
*/
|
*/
|
||||||
bool Running() const
|
bool Running() const
|
||||||
{
|
{
|
||||||
return m_running;
|
return m_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int c_defaultStackSize = 2000000; // fixme: make configurable
|
static const int c_defaultStackSize = 2000000; // fixme: make configurable
|
||||||
|
|
||||||
/* real entry point of the coroutine */
|
/* real entry point of the coroutine */
|
||||||
static void callerStub( intptr_t data )
|
static void callerStub( intptr_t data )
|
||||||
{
|
{
|
||||||
// get pointer to self
|
// get pointer to self
|
||||||
COROUTINE<ReturnType, ArgType>* cor = reinterpret_cast<COROUTINE<ReturnType, ArgType>*>( data );
|
COROUTINE<ReturnType, ArgType>* cor = reinterpret_cast<COROUTINE<ReturnType, ArgType>*>( data );
|
||||||
|
|
||||||
// call the coroutine method
|
// call the coroutine method
|
||||||
cor->m_retVal = cor->m_func( *cor->m_args );
|
cor->m_retVal = cor->m_func( *cor->m_args );
|
||||||
cor->m_running = false;
|
cor->m_running = false;
|
||||||
|
|
||||||
// go back to wherever we came from.
|
// go back to wherever we came from.
|
||||||
boost::context::jump_fcontext( cor->m_self, cor->m_saved, 0 ); //reinterpret_cast<intptr_t>( this ));
|
boost::context::jump_fcontext( cor->m_self, cor->m_saved, 0 ); //reinterpret_cast<intptr_t>( this ));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> struct strip_ref
|
template <typename T> struct strip_ref
|
||||||
{
|
{
|
||||||
typedef T result;
|
typedef T result;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct strip_ref<T&>
|
template <typename T> struct strip_ref<T&>
|
||||||
{
|
{
|
||||||
typedef T result;
|
typedef T result;
|
||||||
};
|
};
|
||||||
|
|
||||||
DELEGATE<ReturnType, ArgType> m_func;
|
DELEGATE<ReturnType, ArgType> m_func;
|
||||||
|
|
||||||
///< pointer to coroutine entry arguments. Stripped of references
|
|
||||||
///< to avoid compiler errors.
|
|
||||||
typename strip_ref<ArgType>::result* m_args;
|
|
||||||
ReturnType m_retVal;
|
|
||||||
|
|
||||||
///< saved caller context
|
|
||||||
boost::context::fcontext_t* m_saved;
|
|
||||||
|
|
||||||
///< saved coroutine context
|
|
||||||
boost::context::fcontext_t* m_self;
|
|
||||||
|
|
||||||
///< coroutine stack
|
///< pointer to coroutine entry arguments. Stripped of references
|
||||||
void* m_stack;
|
///< to avoid compiler errors.
|
||||||
|
typename strip_ref<ArgType>::result* m_args;
|
||||||
|
ReturnType m_retVal;
|
||||||
|
|
||||||
size_t m_stackSize;
|
///< saved caller context
|
||||||
|
boost::context::fcontext_t* m_saved;
|
||||||
|
|
||||||
bool m_running;
|
///< saved coroutine context
|
||||||
|
boost::context::fcontext_t* m_self;
|
||||||
|
|
||||||
|
///< coroutine stack
|
||||||
|
void* m_stack;
|
||||||
|
|
||||||
|
size_t m_stackSize;
|
||||||
|
|
||||||
|
bool m_running;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,38 +28,38 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class DELEGATE
|
* class DELEGATE
|
||||||
* A trivial delegate (pointer to member method of an object) pattern implementation.
|
* A trivial delegate (pointer to member method of an object) pattern implementation.
|
||||||
* Check delegate_example.cpp for a coding sample.
|
* Check delegate_example.cpp for a coding sample.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<class ReturnType, class Arg>
|
template<class ReturnType, class Arg>
|
||||||
class DELEGATE {
|
class DELEGATE {
|
||||||
public:
|
public:
|
||||||
typedef ReturnType (DELEGATE<ReturnType, Arg>::*MemberPointer)( Arg );
|
typedef ReturnType (DELEGATE<ReturnType, Arg>::*MemberPointer)( Arg );
|
||||||
typedef ReturnType _ReturnType;
|
typedef ReturnType _ReturnType;
|
||||||
typedef Arg _ArgType;
|
typedef Arg _ArgType;
|
||||||
|
|
||||||
DELEGATE ()
|
DELEGATE ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
DELEGATE ( T* object, ReturnType (T::*ptr)( Arg ) )
|
DELEGATE ( T* object, ReturnType (T::*ptr)( Arg ) )
|
||||||
{
|
{
|
||||||
m_ptr = reinterpret_cast<MemberPointer>( ptr );
|
m_ptr = reinterpret_cast<MemberPointer>( ptr );
|
||||||
m_object = reinterpret_cast<void *>( object );
|
m_object = reinterpret_cast<void *>( object );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ReturnType operator()( Arg a ) const
|
|
||||||
{
|
|
||||||
DELEGATE<ReturnType, Arg> *casted = reinterpret_cast<DELEGATE<ReturnType, Arg>*>( m_object );
|
|
||||||
return (casted->*m_ptr)(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
ReturnType operator()( Arg a ) const
|
||||||
MemberPointer m_ptr;
|
{
|
||||||
void *m_object;
|
DELEGATE<ReturnType, Arg> *casted = reinterpret_cast<DELEGATE<ReturnType, Arg>*>( m_object );
|
||||||
|
return (casted->*m_ptr)(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemberPointer m_ptr;
|
||||||
|
void *m_object;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,32 +67,32 @@ private:
|
||||||
* Same as DELEGATE, but with no arguments.
|
* Same as DELEGATE, but with no arguments.
|
||||||
*/
|
*/
|
||||||
template<class ReturnType>
|
template<class ReturnType>
|
||||||
class DELEGATE0 {
|
class DELEGATE0 {
|
||||||
public:
|
public:
|
||||||
typedef ReturnType ( DELEGATE0<ReturnType>::*MemberPointer )();
|
typedef ReturnType ( DELEGATE0<ReturnType>::*MemberPointer )();
|
||||||
typedef ReturnType _ReturnType;
|
typedef ReturnType _ReturnType;
|
||||||
|
|
||||||
DELEGATE0 ()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
DELEGATE0 ()
|
||||||
DELEGATE0 ( T* object, ReturnType (T::*ptr)( ) )
|
{
|
||||||
{
|
}
|
||||||
m_ptr = reinterpret_cast<MemberPointer>( ptr );
|
|
||||||
m_object = reinterpret_cast<void*>( object );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
ReturnType operator()( ) const
|
DELEGATE0 ( T* object, ReturnType (T::*ptr)( ) )
|
||||||
{
|
{
|
||||||
DELEGATE0<ReturnType>* casted = reinterpret_cast<DELEGATE0<ReturnType>*>( m_object );
|
m_ptr = reinterpret_cast<MemberPointer>( ptr );
|
||||||
return ( casted->*m_ptr )();
|
m_object = reinterpret_cast<void*>( object );
|
||||||
}
|
};
|
||||||
|
|
||||||
private:
|
|
||||||
MemberPointer m_ptr;
|
ReturnType operator()( ) const
|
||||||
void *m_object;
|
{
|
||||||
|
DELEGATE0<ReturnType>* casted = reinterpret_cast<DELEGATE0<ReturnType>*>( m_object );
|
||||||
|
return ( casted->*m_ptr )();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MemberPointer m_ptr;
|
||||||
|
void *m_object;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,40 +9,40 @@ typedef COROUTINE<int, int> MyCoroutine;
|
||||||
|
|
||||||
class MyClass {
|
class MyClass {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int CountTo(int n)
|
int CountTo(int n)
|
||||||
{
|
{
|
||||||
printf("%s: Coroutine says hi. I will count from 1 to %d and yield each value.\n", __FUNCTION__, n);
|
printf("%s: Coroutine says hi. I will count from 1 to %d and yield each value.\n", __FUNCTION__, n);
|
||||||
for(int i = 1; i <= n; i++)
|
for(int i = 1; i <= n; i++)
|
||||||
{
|
{
|
||||||
printf("%s: Yielding %d\n", __FUNCTION__, i);
|
printf("%s: Yielding %d\n", __FUNCTION__, i);
|
||||||
cofunc.Yield(i);
|
cofunc.Yield(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Run()
|
void Run()
|
||||||
{
|
{
|
||||||
cofunc = MyCoroutine (this, &MyClass::CountTo);
|
cofunc = MyCoroutine (this, &MyClass::CountTo);
|
||||||
printf("%s: Calling coroutine that will count from 1 to 5.\n", __FUNCTION__);
|
printf("%s: Calling coroutine that will count from 1 to 5.\n", __FUNCTION__);
|
||||||
cofunc.Call(5);
|
cofunc.Call(5);
|
||||||
while (cofunc.Running())
|
while (cofunc.Running())
|
||||||
{
|
{
|
||||||
printf("%s: Got value: %d\n", __FUNCTION__, cofunc.ReturnValue());
|
printf("%s: Got value: %d\n", __FUNCTION__, cofunc.ReturnValue());
|
||||||
cofunc.Resume();
|
cofunc.Resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%s: Done!\n", __FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
MyCoroutine cofunc;
|
printf("%s: Done!\n", __FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
|
MyCoroutine cofunc;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
MyClass obj;
|
MyClass obj;
|
||||||
|
|
||||||
obj.Run();
|
obj.Run();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,29 +7,29 @@ using namespace std;
|
||||||
|
|
||||||
class MyClass {
|
class MyClass {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int MyMethod(const string &arg)
|
int MyMethod(const string &arg)
|
||||||
{
|
{
|
||||||
printf("MyClass(this = %p)::MyMethod() called with string '%s', length %d\n", this, arg.c_str(), arg.length());
|
printf("MyClass(this = %p)::MyMethod() called with string '%s', length %d\n", this, arg.c_str(), arg.length());
|
||||||
return arg.length();
|
return arg.length();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef DELEGATE<int, const string&> MyDelegate;
|
typedef DELEGATE<int, const string&> MyDelegate;
|
||||||
|
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
MyClass t1;
|
MyClass t1;
|
||||||
MyClass t2;
|
MyClass t2;
|
||||||
|
|
||||||
|
|
||||||
MyDelegate ptr1 (&t1, &MyClass::MyMethod);
|
MyDelegate ptr1 (&t1, &MyClass::MyMethod);
|
||||||
MyDelegate ptr2 (&t2, &MyClass::MyMethod);
|
MyDelegate ptr2 (&t2, &MyClass::MyMethod);
|
||||||
|
|
||||||
int retval1, retval2;
|
int retval1, retval2;
|
||||||
retval1 = ptr1("apples");
|
retval1 = ptr1("apples");
|
||||||
retval2 = ptr2("cherries");
|
retval2 = ptr2("cherries");
|
||||||
|
|
||||||
printf("Object 1 returned %d, object 2 returned %d\n", retval1, retval2);
|
printf("Object 1 returned %d, object 2 returned %d\n", retval1, retval2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,128 +59,128 @@ typedef DELEGATE<int, TOOL_EVENT&> TOOL_STATE_FUNC;
|
||||||
* Base abstract interface for all kinds of tools.
|
* Base abstract interface for all kinds of tools.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class TOOL_BASE
|
class TOOL_BASE
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TOOL_BASE( TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string( "" ) ) :
|
TOOL_BASE( TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string( "" ) ) :
|
||||||
m_type( aType ),
|
m_type( aType ),
|
||||||
m_toolId( aId ),
|
m_toolId( aId ),
|
||||||
m_toolName( aName ),
|
m_toolName( aName ),
|
||||||
m_toolMgr( NULL ){};
|
m_toolMgr( NULL ){};
|
||||||
|
|
||||||
virtual ~TOOL_BASE() {};
|
virtual ~TOOL_BASE() {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetType()
|
* Function GetType()
|
||||||
* Returns the type of the tool.
|
* Returns the type of the tool.
|
||||||
* @return The type of the tool.
|
* @return The type of the tool.
|
||||||
*/
|
*/
|
||||||
TOOL_Type GetType() const
|
TOOL_Type GetType() const
|
||||||
{
|
{
|
||||||
return m_type;
|
return m_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetId()
|
* Function GetId()
|
||||||
* Returns the unique identifier of the tool. The identifier is set by an instance of
|
* Returns the unique identifier of the tool. The identifier is set by an instance of
|
||||||
* TOOL_MANAGER.
|
* TOOL_MANAGER.
|
||||||
* @return Identifier of the tool.
|
* @return Identifier of the tool.
|
||||||
*/
|
*/
|
||||||
TOOL_ID GetId() const
|
TOOL_ID GetId() const
|
||||||
{
|
{
|
||||||
return m_toolId;
|
return m_toolId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function GetName()
|
* Function GetName()
|
||||||
* Returns the name of the tool. Tool names are expected to obey the format:
|
* Returns the name of the tool. Tool names are expected to obey the format:
|
||||||
* application.ToolName (eg. pcbnew.InteractiveSelection).
|
* application.ToolName (eg. pcbnew.InteractiveSelection).
|
||||||
* @return The name of the tool.
|
* @return The name of the tool.
|
||||||
*/
|
*/
|
||||||
const std::string& GetName() const
|
const std::string& GetName() const
|
||||||
{
|
{
|
||||||
return m_toolName;
|
return m_toolName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetManager()
|
||||||
|
* Returns the instance of TOOL_MANAGER that takes care of the tool.
|
||||||
|
* @return Instance of the TOOL_MANAGER. If there is no TOOL_MANAGER associated, it returns
|
||||||
|
* NULL.
|
||||||
|
*/
|
||||||
|
TOOL_MANAGER* GetManager() const
|
||||||
|
{
|
||||||
|
return m_toolMgr;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Function GetManager()
|
|
||||||
* Returns the instance of TOOL_MANAGER that takes care of the tool.
|
|
||||||
* @return Instance of the TOOL_MANAGER. If there is no TOOL_MANAGER associated, it returns
|
|
||||||
* NULL.
|
|
||||||
*/
|
|
||||||
TOOL_MANAGER* GetManager() const
|
|
||||||
{
|
|
||||||
return m_toolMgr;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class TOOL_MANAGER;
|
friend class TOOL_MANAGER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function attachManager()
|
* Function attachManager()
|
||||||
*
|
*
|
||||||
* Sets the TOOL_MANAGER the tool will belong to.
|
* Sets the TOOL_MANAGER the tool will belong to.
|
||||||
* Called by TOOL_MANAGER::RegisterTool()
|
* Called by TOOL_MANAGER::RegisterTool()
|
||||||
*/
|
*/
|
||||||
void attachManager( TOOL_MANAGER* aManager );
|
void attachManager( TOOL_MANAGER* aManager );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function getView()
|
* Function getView()
|
||||||
*
|
*
|
||||||
* Returns the instance of VIEW object used in the application. It allows tools to draw.
|
* Returns the instance of VIEW object used in the application. It allows tools to draw.
|
||||||
* @return The instance of VIEW.
|
* @return The instance of VIEW.
|
||||||
*/
|
*/
|
||||||
KiGfx::VIEW* getView() const;
|
KiGfx::VIEW* getView() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function getViewControls()
|
* Function getViewControls()
|
||||||
*
|
*
|
||||||
* Returns the instance of VIEW_CONTROLS object used in the application. It allows tools to
|
* Returns the instance of VIEW_CONTROLS object used in the application. It allows tools to
|
||||||
* read & modify user input and its settings (eg. show cursor, enable snapping to grid, etc.)
|
* read & modify user input and its settings (eg. show cursor, enable snapping to grid, etc.)
|
||||||
* @return The instance of VIEW_CONTROLS.
|
* @return The instance of VIEW_CONTROLS.
|
||||||
*/
|
*/
|
||||||
KiGfx::VIEW_CONTROLS* getViewControls() const;
|
KiGfx::VIEW_CONTROLS* getViewControls() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Function getEditFrame()
|
|
||||||
*
|
|
||||||
* Returns the application window object, casted to requested user type.
|
|
||||||
*/
|
|
||||||
template<typename T>
|
|
||||||
T* getEditFrame() const
|
|
||||||
{
|
|
||||||
return static_cast<T*>( getEditFrameInt() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function getModel()
|
* Function getEditFrame()
|
||||||
*
|
*
|
||||||
* Returns the model object if it matches the requested type.
|
* Returns the application window object, casted to requested user type.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* getModel( KICAD_T modelType ) const
|
T* getEditFrame() const
|
||||||
{
|
{
|
||||||
EDA_ITEM* m = getModelInt();
|
return static_cast<T*>( getEditFrameInt() );
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<T*>( m );
|
/**
|
||||||
}
|
* Function getModel()
|
||||||
|
*
|
||||||
|
* Returns the model object if it matches the requested type.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
T* getModel( KICAD_T modelType ) const
|
||||||
|
{
|
||||||
|
EDA_ITEM* m = getModelInt();
|
||||||
|
|
||||||
///> Stores the type of the tool.
|
return static_cast<T*>( m );
|
||||||
TOOL_Type m_type;
|
}
|
||||||
|
|
||||||
///> Unique identifier for the tool, assigned by a TOOL_MANAGER instance.
|
///> Stores the type of the tool.
|
||||||
TOOL_ID m_toolId;
|
TOOL_Type m_type;
|
||||||
|
|
||||||
///> Name of the tool. Names are expected to obey the format application.ToolName
|
///> Unique identifier for the tool, assigned by a TOOL_MANAGER instance.
|
||||||
///> (eg. pcbnew.InteractiveSelection).
|
TOOL_ID m_toolId;
|
||||||
std::string m_toolName;
|
|
||||||
TOOL_MANAGER* m_toolMgr;
|
///> Name of the tool. Names are expected to obey the format application.ToolName
|
||||||
|
///> (eg. pcbnew.InteractiveSelection).
|
||||||
|
std::string m_toolName;
|
||||||
|
TOOL_MANAGER* m_toolMgr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// hide the implementation to avoid spreading half of
|
// hide the implementation to avoid spreading half of
|
||||||
// kicad and wxWidgets headers to the tools that may not need them at all!
|
// kicad and wxWidgets headers to the tools that may not need them at all!
|
||||||
EDA_ITEM* getModelInt() const;
|
EDA_ITEM* getModelInt() const;
|
||||||
wxWindow* getEditFrameInt() const;
|
wxWindow* getEditFrameInt() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,12 +33,12 @@ class TOOL_MANAGER;
|
||||||
class PCB_BASE_FRAME;
|
class PCB_BASE_FRAME;
|
||||||
|
|
||||||
namespace KiGfx {
|
namespace KiGfx {
|
||||||
class VIEW;
|
class VIEW;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class TOOL_DISPATCHER
|
* Class TOOL_DISPATCHER
|
||||||
*
|
*
|
||||||
* - takes wx events,
|
* - takes wx events,
|
||||||
* - fixes all wx quirks (mouse warping, panning, ordering problems, etc)
|
* - fixes all wx quirks (mouse warping, panning, ordering problems, etc)
|
||||||
* - translates coordinates to world space
|
* - translates coordinates to world space
|
||||||
|
|
|
@ -42,63 +42,63 @@ class TOOL_MANAGER;
|
||||||
*/
|
*/
|
||||||
enum TOOL_EventCategory
|
enum TOOL_EventCategory
|
||||||
{
|
{
|
||||||
TC_None = 0x00,
|
TC_None = 0x00,
|
||||||
TC_Mouse = 0x01,
|
TC_Mouse = 0x01,
|
||||||
TC_Keyboard = 0x02,
|
TC_Keyboard = 0x02,
|
||||||
TC_Command = 0x04,
|
TC_Command = 0x04,
|
||||||
TC_Message = 0x08,
|
TC_Message = 0x08,
|
||||||
TC_View = 0x10,
|
TC_View = 0x10,
|
||||||
TC_Any = 0xffffffff
|
TC_Any = 0xffffffff
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TOOL_Actions
|
enum TOOL_Actions
|
||||||
{
|
{
|
||||||
// UI input events
|
// UI input events
|
||||||
TA_None = 0x0000,
|
TA_None = 0x0000,
|
||||||
TA_MouseClick = 0x0001,
|
TA_MouseClick = 0x0001,
|
||||||
TA_MouseUp = 0x0002,
|
TA_MouseUp = 0x0002,
|
||||||
TA_MouseDown = 0x0004,
|
TA_MouseDown = 0x0004,
|
||||||
TA_MouseDrag = 0x0008,
|
TA_MouseDrag = 0x0008,
|
||||||
TA_MouseMotion = 0x0010,
|
TA_MouseMotion = 0x0010,
|
||||||
TA_MouseWheel = 0x0020,
|
TA_MouseWheel = 0x0020,
|
||||||
TA_Mouse = 0x003f,
|
TA_Mouse = 0x003f,
|
||||||
TA_KeyUp = 0x0040,
|
TA_KeyUp = 0x0040,
|
||||||
TA_KeyDown = 0x0080,
|
TA_KeyDown = 0x0080,
|
||||||
TA_Keyboard = TA_KeyUp | TA_KeyDown,
|
TA_Keyboard = TA_KeyUp | TA_KeyDown,
|
||||||
|
|
||||||
// View related events
|
// View related events
|
||||||
TA_ViewRefresh = 0x0100,
|
TA_ViewRefresh = 0x0100,
|
||||||
TA_ViewZoom = 0x0200,
|
TA_ViewZoom = 0x0200,
|
||||||
TA_ViewPan = 0x0400,
|
TA_ViewPan = 0x0400,
|
||||||
TA_ViewDirty = 0x0800,
|
TA_ViewDirty = 0x0800,
|
||||||
TA_ChangeLayer = 0x1000,
|
TA_ChangeLayer = 0x1000,
|
||||||
|
|
||||||
// Tool cancel event. Issued automagically when the user hits escape or selects End Tool from
|
// Tool cancel event. Issued automagically when the user hits escape or selects End Tool from
|
||||||
// the context menu.
|
// the context menu.
|
||||||
TA_CancelTool = 0x2000,
|
TA_CancelTool = 0x2000,
|
||||||
|
|
||||||
// Context menu update. Issued whenever context menu is open and the user hovers the mouse
|
// Context menu update. Issued whenever context menu is open and the user hovers the mouse
|
||||||
// over one of choices. Used in dynamic highligting in disambiguation menu
|
// over one of choices. Used in dynamic highligting in disambiguation menu
|
||||||
TA_ContextMenuUpdate = 0x4000,
|
TA_ContextMenuUpdate = 0x4000,
|
||||||
|
|
||||||
// Context menu choice. Sent if the user picked something from the context menu or
|
// Context menu choice. Sent if the user picked something from the context menu or
|
||||||
// closed it without selecting anything.
|
// closed it without selecting anything.
|
||||||
TA_ContextMenuChoice = 0x8000,
|
TA_ContextMenuChoice = 0x8000,
|
||||||
|
|
||||||
// Tool action (allows to control tools)
|
// Tool action (allows to control tools)
|
||||||
TA_Action = 0x10000,
|
TA_Action = 0x10000,
|
||||||
|
|
||||||
TA_Any = 0xffffffff
|
TA_Any = 0xffffffff
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TOOL_MouseButtons
|
enum TOOL_MouseButtons
|
||||||
{
|
{
|
||||||
MB_None = 0x0,
|
MB_None = 0x0,
|
||||||
MB_Left = 0x1,
|
MB_Left = 0x1,
|
||||||
MB_Right = 0x2,
|
MB_Right = 0x2,
|
||||||
MB_Middle = 0x4,
|
MB_Middle = 0x4,
|
||||||
MB_ButtonMask = MB_Left | MB_Right | MB_Middle,
|
MB_ButtonMask = MB_Left | MB_Right | MB_Middle,
|
||||||
MB_Any = 0xffffffff
|
MB_Any = 0xffffffff
|
||||||
};
|
};
|
||||||
|
|
||||||
enum TOOL_Modifiers
|
enum TOOL_Modifiers
|
||||||
|
@ -120,14 +120,14 @@ enum TOOL_ActionScope
|
||||||
/// Defines when a context menu is opened.
|
/// Defines when a context menu is opened.
|
||||||
enum CONTEXT_MENU_TRIGGER
|
enum CONTEXT_MENU_TRIGGER
|
||||||
{
|
{
|
||||||
CMENU_BUTTON = 0, // On the right button
|
CMENU_BUTTON = 0, // On the right button
|
||||||
CMENU_NOW, // Right now (after TOOL_INTERACTIVE::SetContextMenu)
|
CMENU_NOW, // Right now (after TOOL_INTERACTIVE::SetContextMenu)
|
||||||
CMENU_OFF // Never
|
CMENU_OFF // Never
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class TOOL_EVENT
|
* Class TOOL_EVENT
|
||||||
*
|
*
|
||||||
* Generic, UI-independent tool event.
|
* Generic, UI-independent tool event.
|
||||||
*/
|
*/
|
||||||
class TOOL_EVENT
|
class TOOL_EVENT
|
||||||
|
@ -359,9 +359,9 @@ private:
|
||||||
|
|
||||||
typedef boost::optional<TOOL_EVENT> OPT_TOOL_EVENT;
|
typedef boost::optional<TOOL_EVENT> OPT_TOOL_EVENT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class TOOL_EVENT_LIST
|
* Class TOOL_EVENT_LIST
|
||||||
*
|
*
|
||||||
* A list of TOOL_EVENTs, with overloaded || operators allowing for
|
* A list of TOOL_EVENTs, with overloaded || operators allowing for
|
||||||
* concatenating TOOL_EVENTs with little code.
|
* concatenating TOOL_EVENTs with little code.
|
||||||
*/
|
*/
|
||||||
|
@ -473,20 +473,20 @@ private:
|
||||||
|
|
||||||
inline const TOOL_EVENT_LIST operator||( const TOOL_EVENT& a, const TOOL_EVENT& b )
|
inline const TOOL_EVENT_LIST operator||( const TOOL_EVENT& a, const TOOL_EVENT& b )
|
||||||
{
|
{
|
||||||
TOOL_EVENT_LIST l;
|
TOOL_EVENT_LIST l;
|
||||||
|
|
||||||
l.Add( a );
|
l.Add( a );
|
||||||
l.Add( b );
|
l.Add( b );
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const TOOL_EVENT_LIST operator||( const TOOL_EVENT& a, const TOOL_EVENT_LIST& b )
|
inline const TOOL_EVENT_LIST operator||( const TOOL_EVENT& a, const TOOL_EVENT_LIST& b )
|
||||||
{
|
{
|
||||||
TOOL_EVENT_LIST l( b );
|
TOOL_EVENT_LIST l( b );
|
||||||
|
|
||||||
l.Add( a );
|
l.Add( a );
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -39,23 +39,23 @@ public:
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
* Creates a tool with given id & name. The name must be unique. */
|
* Creates a tool with given id & name. The name must be unique. */
|
||||||
TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName );
|
TOOL_INTERACTIVE( TOOL_ID aId, const std::string& aName );
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* Creates a tool with given name. The name must be unique. */
|
|
||||||
TOOL_INTERACTIVE( const std::string& aName );
|
|
||||||
virtual ~TOOL_INTERACTIVE();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Reset()
|
* Constructor
|
||||||
* Brings the tool to a known, initial state. If the tool claimed anything from
|
*
|
||||||
* the model or the view, it must release it when its reset.
|
* Creates a tool with given name. The name must be unique. */
|
||||||
*/
|
TOOL_INTERACTIVE( const std::string& aName );
|
||||||
virtual void Reset() = 0;
|
virtual ~TOOL_INTERACTIVE();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Function Reset()
|
||||||
|
* Brings the tool to a known, initial state. If the tool claimed anything from
|
||||||
|
* the model or the view, it must release it when its reset.
|
||||||
|
*/
|
||||||
|
virtual void Reset() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
* Function Init()
|
* Function Init()
|
||||||
* Init() is called once upon a registration of the tool.
|
* Init() is called once upon a registration of the tool.
|
||||||
*
|
*
|
||||||
|
@ -66,58 +66,58 @@ public:
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function SetContextMenu()
|
* Function SetContextMenu()
|
||||||
*
|
*
|
||||||
* Assigns a context menu and tells when it should be activated.
|
* Assigns a context menu and tells when it should be activated.
|
||||||
* @param aMenu is the menu to be assigned.
|
* @param aMenu is the menu to be assigned.
|
||||||
* @param aTrigger determines conditions upon which the context menu is activated.
|
* @param aTrigger determines conditions upon which the context menu is activated.
|
||||||
*/
|
*/
|
||||||
void SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger = CMENU_BUTTON );
|
void SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger = CMENU_BUTTON );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Go()
|
* Function Go()
|
||||||
*
|
*
|
||||||
* Defines which state (aStateFunc) to go when a certain event arrives (aConditions).
|
* Defines which state (aStateFunc) to go when a certain event arrives (aConditions).
|
||||||
* No conditions means any event.
|
* No conditions means any event.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
void Go( int (T::*aStateFunc)( TOOL_EVENT& ),
|
void Go( int (T::*aStateFunc)( TOOL_EVENT& ),
|
||||||
const TOOL_EVENT_LIST& aConditions = TOOL_EVENT( TC_Any, TA_Any ) );
|
const TOOL_EVENT_LIST& aConditions = TOOL_EVENT( TC_Any, TA_Any ) );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Wait()
|
* Function Wait()
|
||||||
*
|
*
|
||||||
* Suspends execution of the tool until an event specified in aEventList arrives.
|
* Suspends execution of the tool until an event specified in aEventList arrives.
|
||||||
* No parameters means waiting for any event.
|
* No parameters means waiting for any event.
|
||||||
*/
|
*/
|
||||||
OPT_TOOL_EVENT Wait( const TOOL_EVENT_LIST& aEventList = TOOL_EVENT ( TC_Any, TA_Any ) );
|
OPT_TOOL_EVENT Wait( const TOOL_EVENT_LIST& aEventList = TOOL_EVENT ( TC_Any, TA_Any ) );
|
||||||
|
|
||||||
/** functions below are not yet implemented - their interface may change */
|
/** functions below are not yet implemented - their interface may change */
|
||||||
/*template<class Parameters, class ReturnValue>
|
/*template<class Parameters, class ReturnValue>
|
||||||
bool InvokeTool( const std::string& aToolName, const Parameters& parameters,
|
bool InvokeTool( const std::string& aToolName, const Parameters& parameters,
|
||||||
ReturnValue& returnValue );
|
ReturnValue& returnValue );
|
||||||
|
|
||||||
template<class Parameters, class ReturnValue>
|
template<class Parameters, class ReturnValue>
|
||||||
bool InvokeWindow( const std::string& aWindowName, const Parameters& parameters,
|
bool InvokeWindow( const std::string& aWindowName, const Parameters& parameters,
|
||||||
ReturnValue& returnValue );
|
ReturnValue& returnValue );
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void Yield( const T& returnValue );*/
|
void Yield( const T& returnValue );*/
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/* helper functions for constructing events for Wait() and Go() with less typing */
|
/* helper functions for constructing events for Wait() and Go() with less typing */
|
||||||
const TOOL_EVENT evActivate( std::string aToolName = "" );
|
const TOOL_EVENT evActivate( std::string aToolName = "" );
|
||||||
const TOOL_EVENT evCommand( int aCommandId = -1 );
|
const TOOL_EVENT evCommand( int aCommandId = -1 );
|
||||||
const TOOL_EVENT evCommand( std::string aCommandStr = "" );
|
const TOOL_EVENT evCommand( std::string aCommandStr = "" );
|
||||||
const TOOL_EVENT evMotion();
|
const TOOL_EVENT evMotion();
|
||||||
const TOOL_EVENT evClick( int aButton = MB_Any );
|
const TOOL_EVENT evClick( int aButton = MB_Any );
|
||||||
const TOOL_EVENT evDrag( int aButton = MB_Any );
|
const TOOL_EVENT evDrag( int aButton = MB_Any );
|
||||||
const TOOL_EVENT evButtonUp( int aButton = MB_Any );
|
const TOOL_EVENT evButtonUp( int aButton = MB_Any );
|
||||||
const TOOL_EVENT evButtonDown(int aButton = MB_Any );
|
const TOOL_EVENT evButtonDown(int aButton = MB_Any );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void goInternal( TOOL_STATE_FUNC& aState, const TOOL_EVENT_LIST& aConditions );
|
void goInternal( TOOL_STATE_FUNC& aState, const TOOL_EVENT_LIST& aConditions );
|
||||||
};
|
};
|
||||||
|
|
||||||
// hide TOOL_MANAGER implementation
|
// hide TOOL_MANAGER implementation
|
||||||
|
@ -125,8 +125,8 @@ template<class T>
|
||||||
void TOOL_INTERACTIVE::Go( int (T::*aStateFunc)( TOOL_EVENT& ),
|
void TOOL_INTERACTIVE::Go( int (T::*aStateFunc)( TOOL_EVENT& ),
|
||||||
const TOOL_EVENT_LIST& aConditions )
|
const TOOL_EVENT_LIST& aConditions )
|
||||||
{
|
{
|
||||||
TOOL_STATE_FUNC sptr( static_cast<T*>( this ), aStateFunc );
|
TOOL_STATE_FUNC sptr( static_cast<T*>( this ), aStateFunc );
|
||||||
goInternal( sptr, aConditions );
|
goInternal( sptr, aConditions );
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -122,7 +122,7 @@ public:
|
||||||
virtual const VECTOR2D GetCursorPosition() const = 0;
|
virtual const VECTOR2D GetCursorPosition() const = 0;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function ForceCursorPosition()
|
* Function ForceCursorPosition()
|
||||||
* Places the cursor immediately at a given point. Mouse movement is ignored.
|
* Places the cursor immediately at a given point. Mouse movement is ignored.
|
||||||
* @param aEnabled enable forced cursor position
|
* @param aEnabled enable forced cursor position
|
||||||
|
|
|
@ -279,7 +279,7 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
|
||||||
NETINFO_ITEM* net = ( (BOARD*) aTrack->GetParent() )->FindNet( netNumber );
|
NETINFO_ITEM* net = ( (BOARD*) aTrack->GetParent() )->FindNet( netNumber );
|
||||||
if( !net )
|
if( !net )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string netName = std::string( net->GetShortNetname().mb_str() );
|
std::string netName = std::string( net->GetShortNetname().mb_str() );
|
||||||
VECTOR2D textPosition = start + line / 2.0; // center of the track
|
VECTOR2D textPosition = start + line / 2.0; // center of the track
|
||||||
double textOrientation = -atan( line.y / line.x );
|
double textOrientation = -atan( line.y / line.x );
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
/**
|
/**
|
||||||
* Class PNS_ITEMSET
|
* Class PNS_ITEMSET
|
||||||
*
|
*
|
||||||
* Holds a list of board items, that can be filtered against net, kinds,
|
* Holds a list of board items, that can be filtered against net, kinds,
|
||||||
* layers, etc.
|
* layers, etc.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,9 @@
|
||||||
/**
|
/**
|
||||||
* Class PNS_JOINT
|
* Class PNS_JOINT
|
||||||
*
|
*
|
||||||
* Represents a 2D point on a given set of layers and belonging to a certain
|
* Represents a 2D point on a given set of layers and belonging to a certain
|
||||||
* net, that links together a number of board items.
|
* net, that links together a number of board items.
|
||||||
* A hash table of joints is used by the router to follow connectivity between
|
* A hash table of joints is used by the router to follow connectivity between
|
||||||
* the items.
|
* the items.
|
||||||
**/
|
**/
|
||||||
class PNS_JOINT : public PNS_ITEM
|
class PNS_JOINT : public PNS_ITEM
|
||||||
|
@ -53,8 +53,8 @@ public:
|
||||||
PNS_JOINT() :
|
PNS_JOINT() :
|
||||||
PNS_ITEM( JOINT ) {}
|
PNS_ITEM( JOINT ) {}
|
||||||
|
|
||||||
PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
||||||
int aNet = -1 ) :
|
int aNet = -1 ) :
|
||||||
PNS_ITEM( JOINT )
|
PNS_ITEM( JOINT )
|
||||||
{
|
{
|
||||||
m_tag.pos = aPos;
|
m_tag.pos = aPos;
|
||||||
|
@ -78,14 +78,14 @@ public:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
///> Returns true if the joint is a trivial line corner, connecting two
|
///> Returns true if the joint is a trivial line corner, connecting two
|
||||||
/// segments of the same net, on the same layer.
|
/// segments of the same net, on the same layer.
|
||||||
bool IsLineCorner() const
|
bool IsLineCorner() const
|
||||||
{
|
{
|
||||||
if( m_linkedItems.size() != 2 )
|
if( m_linkedItems.size() != 2 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( m_linkedItems[0]->GetKind() != SEGMENT ||
|
if( m_linkedItems[0]->GetKind() != SEGMENT ||
|
||||||
m_linkedItems[1]->GetKind() != SEGMENT )
|
m_linkedItems[1]->GetKind() != SEGMENT )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ public:
|
||||||
///> Links the joint to a given board item (when it's added to the PNS_NODE)
|
///> Links the joint to a given board item (when it's added to the PNS_NODE)
|
||||||
void Link( PNS_ITEM* aItem )
|
void Link( PNS_ITEM* aItem )
|
||||||
{
|
{
|
||||||
LinkedItems::iterator f = std::find( m_linkedItems.begin(),
|
LinkedItems::iterator f = std::find( m_linkedItems.begin(),
|
||||||
m_linkedItems.end(), aItem );
|
m_linkedItems.end(), aItem );
|
||||||
|
|
||||||
if( f != m_linkedItems.end() )
|
if( f != m_linkedItems.end() )
|
||||||
|
@ -112,7 +112,7 @@ public:
|
||||||
///> Returns true if the joint became dangling after unlinking.
|
///> Returns true if the joint became dangling after unlinking.
|
||||||
bool Unlink( PNS_ITEM* aItem )
|
bool Unlink( PNS_ITEM* aItem )
|
||||||
{
|
{
|
||||||
LinkedItems::iterator f = std::find( m_linkedItems.begin(),
|
LinkedItems::iterator f = std::find( m_linkedItems.begin(),
|
||||||
m_linkedItems.end(), aItem );
|
m_linkedItems.end(), aItem );
|
||||||
|
|
||||||
if( f != m_linkedItems.end() )
|
if( f != m_linkedItems.end() )
|
||||||
|
@ -142,7 +142,7 @@ public:
|
||||||
{
|
{
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
for( LinkedItems::const_iterator i = m_linkedItems.begin();
|
for( LinkedItems::const_iterator i = m_linkedItems.begin();
|
||||||
i != m_linkedItems.end(); ++i )
|
i != m_linkedItems.end(); ++i )
|
||||||
if( (*i)->GetKind() & aMask )
|
if( (*i)->GetKind() & aMask )
|
||||||
n++;
|
n++;
|
||||||
|
@ -172,7 +172,7 @@ public:
|
||||||
|
|
||||||
bool Overlaps( const PNS_JOINT& rhs ) const
|
bool Overlaps( const PNS_JOINT& rhs ) const
|
||||||
{
|
{
|
||||||
return m_tag.pos == rhs.m_tag.pos &&
|
return m_tag.pos == rhs.m_tag.pos &&
|
||||||
m_tag.net == rhs.m_tag.net && m_layers.Overlaps( rhs.m_layers );
|
m_tag.net == rhs.m_tag.net && m_layers.Overlaps( rhs.m_layers );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
// hash function & comparison operator for boost::unordered_map<>
|
// hash function & comparison operator for boost::unordered_map<>
|
||||||
inline bool operator==( PNS_JOINT::HashTag const& p1,
|
inline bool operator==( PNS_JOINT::HashTag const& p1,
|
||||||
PNS_JOINT::HashTag const& p2 )
|
PNS_JOINT::HashTag const& p2 )
|
||||||
{
|
{
|
||||||
return p1.pos == p2.pos && p1.net == p2.net;
|
return p1.pos == p2.pos && p1.net == p2.net;
|
||||||
|
|
|
@ -434,7 +434,7 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle,
|
||||||
path.Append( l_hull.CPoint( j ) );
|
path.Append( l_hull.CPoint( j ) );
|
||||||
li = l_orig.Find( l_hull.CPoint( j ) );
|
li = l_orig.Find( l_hull.CPoint( j ) );
|
||||||
|
|
||||||
if( li >= 0 && ( li == (l_orig.PointCount() - 1 ) ||
|
if( li >= 0 && ( li == (l_orig.PointCount() - 1 ) ||
|
||||||
outside[li + 1]) )
|
outside[li + 1]) )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -514,7 +514,7 @@ bool PNS_LINE::walkScan( const SHAPE_LINE_CHAIN& line,
|
||||||
{
|
{
|
||||||
index_l = (reverse ? sc - 1 - i : i);
|
index_l = (reverse ? sc - 1 - i : i);
|
||||||
ip = s.a;
|
ip = s.a;
|
||||||
printf( "vertex %d on-%s %d\n", index_l,
|
printf( "vertex %d on-%s %d\n", index_l,
|
||||||
is_vertex ? "vertex" : "edge", index_o );
|
is_vertex ? "vertex" : "edge", index_o );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -523,7 +523,7 @@ bool PNS_LINE::walkScan( const SHAPE_LINE_CHAIN& line,
|
||||||
{
|
{
|
||||||
index_l = (reverse ? sc - 1 - i - 1 : i + 1);
|
index_l = (reverse ? sc - 1 - i - 1 : i + 1);
|
||||||
ip = s.b;
|
ip = s.b;
|
||||||
printf( "vertex %d on-%s %d\n", index_l,
|
printf( "vertex %d on-%s %d\n", index_l,
|
||||||
is_vertex ? "vertex" : "edge", index_o );
|
is_vertex ? "vertex" : "edge", index_o );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -562,7 +562,7 @@ bool PNS_LINE::Walkaround( SHAPE_LINE_CHAIN obstacle,
|
||||||
if( line.SegmentCount() < 1 )
|
if( line.SegmentCount() < 1 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( obstacle.PointInside( line.CPoint( 0 ) ) ||
|
if( obstacle.PointInside( line.CPoint( 0 ) ) ||
|
||||||
obstacle.PointInside( line.CPoint( -1 ) ) )
|
obstacle.PointInside( line.CPoint( -1 ) ) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -714,7 +714,7 @@ bool PNS_LINE::Is45Degree()
|
||||||
const SEG& s = m_line.CSegment( i );
|
const SEG& s = m_line.CSegment( i );
|
||||||
|
|
||||||
double angle = 180.0 / M_PI *
|
double angle = 180.0 / M_PI *
|
||||||
atan2( (double) s.b.y - (double) s.a.y,
|
atan2( (double) s.b.y - (double) s.a.y,
|
||||||
(double) s.b.x - (double) s.a.x );
|
(double) s.b.x - (double) s.a.x );
|
||||||
|
|
||||||
if( angle < 0 )
|
if( angle < 0 )
|
||||||
|
|
|
@ -38,17 +38,17 @@ class PNS_VIA;
|
||||||
/**
|
/**
|
||||||
* Class PNS_LINE
|
* Class PNS_LINE
|
||||||
*
|
*
|
||||||
* Represents a track on a PCB, connecting two non-trivial joints (that is,
|
* Represents a track on a PCB, connecting two non-trivial joints (that is,
|
||||||
* vias, pads, junctions between multiple traces or two traces different widths
|
* vias, pads, junctions between multiple traces or two traces different widths
|
||||||
* and combinations of these). PNS_LINEs are NOT stored in the model (PNS_NODE).
|
* and combinations of these). PNS_LINEs are NOT stored in the model (PNS_NODE).
|
||||||
* Instead, they are assembled on-the-fly, based on a via/pad/segment that
|
* Instead, they are assembled on-the-fly, based on a via/pad/segment that
|
||||||
* belongs/begins them.
|
* belongs/begins them.
|
||||||
*
|
*
|
||||||
* PNS_LINEs can be either loose (consisting of segments that do not belong to
|
* PNS_LINEs can be either loose (consisting of segments that do not belong to
|
||||||
* any PNS_NODE) or owned (with segments taken from a PNS_NODE) - these are
|
* any PNS_NODE) or owned (with segments taken from a PNS_NODE) - these are
|
||||||
* returned by PNS_NODE::AssembleLine and friends.
|
* returned by PNS_NODE::AssembleLine and friends.
|
||||||
*
|
*
|
||||||
* A PNS_LINE may have a PNS_VIA attached at its and - this is used by via
|
* A PNS_LINE may have a PNS_VIA attached at its and - this is used by via
|
||||||
* dragging/force propagation stuff.
|
* dragging/force propagation stuff.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ public:
|
||||||
m_segmentRefs->push_back( aSeg );
|
m_segmentRefs->push_back( aSeg );
|
||||||
}
|
}
|
||||||
|
|
||||||
///> Returns a list of segments from the owning node that constitute this
|
///> Returns a list of segments from the owning node that constitute this
|
||||||
///> line (or NULL if the line is loose)
|
///> line (or NULL if the line is loose)
|
||||||
LinkedSegments* GetLinkedSegments()
|
LinkedSegments* GetLinkedSegments()
|
||||||
{
|
{
|
||||||
|
@ -157,7 +157,7 @@ public:
|
||||||
aSeg ) != m_segmentRefs->end();
|
aSeg ) != m_segmentRefs->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
///> Returns this line, but clipped to the nearest obstacle
|
///> Returns this line, but clipped to the nearest obstacle
|
||||||
///> along, to avoid collision.
|
///> along, to avoid collision.
|
||||||
const PNS_LINE ClipToNearestObstacle( PNS_NODE* aNode ) const;
|
const PNS_LINE ClipToNearestObstacle( PNS_NODE* aNode ) const;
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ public:
|
||||||
///> Returns the number of corners of angles specified by mask aAngles.
|
///> Returns the number of corners of angles specified by mask aAngles.
|
||||||
int CountCorners( int aAngles );
|
int CountCorners( int aAngles );
|
||||||
|
|
||||||
///> Calculates a line thightly wrapping a convex hull
|
///> Calculates a line thightly wrapping a convex hull
|
||||||
///> of an obstacle object (aObstacle).
|
///> of an obstacle object (aObstacle).
|
||||||
///> aPrePath = path from origin to the obstacle
|
///> aPrePath = path from origin to the obstacle
|
||||||
///> aWalkaroundPath = path around the obstacle
|
///> aWalkaroundPath = path around the obstacle
|
||||||
|
|
|
@ -63,7 +63,7 @@ void PNS_LINE_PLACER::ApplySettings( const PNS_ROUTING_SETTINGS& aSettings )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet,
|
void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet,
|
||||||
int aWidth, int aLayer )
|
int aWidth, int aLayer )
|
||||||
{
|
{
|
||||||
m_direction = m_initial_direction;
|
m_direction = m_initial_direction;
|
||||||
|
@ -177,14 +177,14 @@ bool PNS_LINE_PLACER::handlePullback()
|
||||||
DIRECTION_45 last_tail( tail.Segment( -1 ) );
|
DIRECTION_45 last_tail( tail.Segment( -1 ) );
|
||||||
DIRECTION_45::AngleType angle = first_head.Angle( last_tail );
|
DIRECTION_45::AngleType angle = first_head.Angle( last_tail );
|
||||||
|
|
||||||
// case 1: we have a defined routing direction, and the currently computed
|
// case 1: we have a defined routing direction, and the currently computed
|
||||||
// head goes in different one.
|
// head goes in different one.
|
||||||
bool pullback_1 = false; // (m_direction != DIRECTION_45::UNDEFINED && m_direction != first_head);
|
bool pullback_1 = false; // (m_direction != DIRECTION_45::UNDEFINED && m_direction != first_head);
|
||||||
|
|
||||||
// case 2: regardless of the current routing direction, if the tail/head
|
// case 2: regardless of the current routing direction, if the tail/head
|
||||||
// extremities form an acute or right angle, reduce the tail by one segment
|
// extremities form an acute or right angle, reduce the tail by one segment
|
||||||
// (and hope that further iterations) will result with a cleaner trace
|
// (and hope that further iterations) will result with a cleaner trace
|
||||||
bool pullback_2 = (angle == DIRECTION_45::ANG_RIGHT ||
|
bool pullback_2 = (angle == DIRECTION_45::ANG_RIGHT ||
|
||||||
angle == DIRECTION_45::ANG_ACUTE);
|
angle == DIRECTION_45::ANG_ACUTE);
|
||||||
|
|
||||||
if( pullback_1 || pullback_2 )
|
if( pullback_1 || pullback_2 )
|
||||||
|
@ -197,7 +197,7 @@ bool PNS_LINE_PLACER::handlePullback()
|
||||||
n % last_tail.Format().c_str() % first_head.Format().c_str() );
|
n % last_tail.Format().c_str() % first_head.Format().c_str() );
|
||||||
|
|
||||||
// erase the last point in the tail, hoping that the next iteration will
|
// erase the last point in the tail, hoping that the next iteration will
|
||||||
// result with a head trace that starts with a segment following our
|
// result with a head trace that starts with a segment following our
|
||||||
// current direction.
|
// current direction.
|
||||||
if( n < 2 )
|
if( n < 2 )
|
||||||
tail.Clear(); // don't leave a single-point tail
|
tail.Clear(); // don't leave a single-point tail
|
||||||
|
@ -239,7 +239,7 @@ bool PNS_LINE_PLACER::reduceTail( const VECTOR2I& aEnd )
|
||||||
const SEG s = tail.CSegment( i );
|
const SEG s = tail.CSegment( i );
|
||||||
DIRECTION_45 dir( s );
|
DIRECTION_45 dir( s );
|
||||||
|
|
||||||
// calculate a replacement route and check if it matches
|
// calculate a replacement route and check if it matches
|
||||||
// the direction of the segment to be replaced
|
// the direction of the segment to be replaced
|
||||||
SHAPE_LINE_CHAIN replacement = dir.BuildInitialTrace( s.a, aEnd );
|
SHAPE_LINE_CHAIN replacement = dir.BuildInitialTrace( s.a, aEnd );
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ bool PNS_LINE_PLACER::mergeHead()
|
||||||
SHAPE_LINE_CHAIN& head = m_head.GetLine();
|
SHAPE_LINE_CHAIN& head = m_head.GetLine();
|
||||||
SHAPE_LINE_CHAIN& tail = m_tail.GetLine();
|
SHAPE_LINE_CHAIN& tail = m_tail.GetLine();
|
||||||
|
|
||||||
const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE |
|
const int ForbiddenAngles = DIRECTION_45::ANG_ACUTE |
|
||||||
DIRECTION_45::ANG_HALF_FULL |
|
DIRECTION_45::ANG_HALF_FULL |
|
||||||
DIRECTION_45::ANG_UNDEFINED;
|
DIRECTION_45::ANG_UNDEFINED;
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead )
|
||||||
|
|
||||||
if( v.PushoutForce( m_shove->GetCurrentNode(), lead, force, true, 20 ) )
|
if( v.PushoutForce( m_shove->GetCurrentNode(), lead, force, true, 20 ) )
|
||||||
{
|
{
|
||||||
SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace(
|
SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace(
|
||||||
aHead.GetCLine().CPoint( 0 ),
|
aHead.GetCLine().CPoint( 0 ),
|
||||||
aHead.GetCLine().CPoint( -1 ) + force );
|
aHead.GetCLine().CPoint( -1 ) + force );
|
||||||
aHead = PNS_LINE( aHead, line );
|
aHead = PNS_LINE( aHead, line );
|
||||||
|
@ -379,7 +379,7 @@ bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool PNS_LINE_PLACER::routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead,
|
bool PNS_LINE_PLACER::routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead,
|
||||||
bool aCwWalkaround )
|
bool aCwWalkaround )
|
||||||
{
|
{
|
||||||
// STAGE 1: route a simple two-segment trace between m_p_start and aP...
|
// STAGE 1: route a simple two-segment trace between m_p_start and aP...
|
||||||
|
@ -543,7 +543,7 @@ bool PNS_LINE_PLACER::optimizeTailHeadTransition()
|
||||||
PNS_LINE new_head( m_tail, opt_line );
|
PNS_LINE new_head( m_tail, opt_line );
|
||||||
|
|
||||||
// and see if it could be made simpler by merging obtuse/collnear segments.
|
// and see if it could be made simpler by merging obtuse/collnear segments.
|
||||||
// If so, replace the (threshold) last tail points and the head with
|
// If so, replace the (threshold) last tail points and the head with
|
||||||
// the optimized line
|
// the optimized line
|
||||||
|
|
||||||
// if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS))
|
// if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS))
|
||||||
|
|
|
@ -39,7 +39,7 @@ class PNS_ROUTER_BASE;
|
||||||
/**
|
/**
|
||||||
* Class PNS_LINE_PLACER
|
* Class PNS_LINE_PLACER
|
||||||
*
|
*
|
||||||
* Interactively routes a single track. Runs shove and walkaround
|
* Interactively routes a single track. Runs shove and walkaround
|
||||||
* algorithms when needed.
|
* algorithms when needed.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -63,9 +63,9 @@ public:
|
||||||
/**
|
/**
|
||||||
* Function Route()
|
* Function Route()
|
||||||
*
|
*
|
||||||
* Re-routes the current track to point aP. Returns true, when routing has
|
* Re-routes the current track to point aP. Returns true, when routing has
|
||||||
* completed successfully (i.e. the trace end has reached point aP), and false
|
* completed successfully (i.e. the trace end has reached point aP), and false
|
||||||
* if the trace was stuck somewhere on the way. May call routeStep()
|
* if the trace was stuck somewhere on the way. May call routeStep()
|
||||||
* repetitively due to mouse smoothing.
|
* repetitively due to mouse smoothing.
|
||||||
* @param aP ending point of current route.
|
* @param aP ending point of current route.
|
||||||
* @return true, if the routing is complete.
|
* @return true, if the routing is complete.
|
||||||
|
@ -80,7 +80,7 @@ public:
|
||||||
///> Returns the "head" of the line being placed, that is the volatile part
|
///> Returns the "head" of the line being placed, that is the volatile part
|
||||||
///> that has not been settled yet
|
///> that has not been settled yet
|
||||||
const PNS_LINE& GetHead() const { return m_head; }
|
const PNS_LINE& GetHead() const { return m_head; }
|
||||||
///> Returns the "tail" of the line being placed the part that has been
|
///> Returns the "tail" of the line being placed the part that has been
|
||||||
///> fixed already (follow mouse mode only)
|
///> fixed already (follow mouse mode only)
|
||||||
const PNS_LINE& GetTail() const { return m_tail; }
|
const PNS_LINE& GetTail() const { return m_tail; }
|
||||||
|
|
||||||
|
@ -99,9 +99,9 @@ public:
|
||||||
return m_p_start;
|
return m_p_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
///> Returns all items in the world that have been affected by the routing
|
///> Returns all items in the world that have been affected by the routing
|
||||||
///> operation. Used to update data structures of the host application
|
///> operation. Used to update data structures of the host application
|
||||||
void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved,
|
void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved,
|
||||||
PNS_NODE::ItemVector& aAdded );
|
PNS_NODE::ItemVector& aAdded );
|
||||||
|
|
||||||
///> Toggles the current posture (straight/diagonal) of the trace head.
|
///> Toggles the current posture (straight/diagonal) of the trace head.
|
||||||
|
@ -114,30 +114,30 @@ private:
|
||||||
static const double m_shoveLengthThreshold = 1.7;
|
static const double m_shoveLengthThreshold = 1.7;
|
||||||
|
|
||||||
bool handleViaPlacement( PNS_LINE& aHead );
|
bool handleViaPlacement( PNS_LINE& aHead );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function checkObtusity()
|
* Function checkObtusity()
|
||||||
*
|
*
|
||||||
* Helper that checks if segments a and b form an obtuse angle
|
* Helper that checks if segments a and b form an obtuse angle
|
||||||
* (in 45-degree regime).
|
* (in 45-degree regime).
|
||||||
* @return true, if angle (a, b) is obtuse
|
* @return true, if angle (a, b) is obtuse
|
||||||
*/
|
*/
|
||||||
bool checkObtusity( const SEG& a, const SEG& b ) const;
|
bool checkObtusity( const SEG& a, const SEG& b ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function handleSelfIntersections()
|
* Function handleSelfIntersections()
|
||||||
*
|
*
|
||||||
* Checks if the head of the track intersects its tail. If so, cuts the
|
* Checks if the head of the track intersects its tail. If so, cuts the
|
||||||
* tail up to the intersecting segment and fixes the head direction to match
|
* tail up to the intersecting segment and fixes the head direction to match
|
||||||
* the last segment before the cut.
|
* the last segment before the cut.
|
||||||
* @return true if the line has been changed.
|
* @return true if the line has been changed.
|
||||||
*/
|
*/
|
||||||
bool handleSelfIntersections();
|
bool handleSelfIntersections();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function handlePullback()
|
* Function handlePullback()
|
||||||
*
|
*
|
||||||
* Deals with pull-back: reduces the tail if head trace is moved backwards
|
* Deals with pull-back: reduces the tail if head trace is moved backwards
|
||||||
* wrs to the current tail direction.
|
* wrs to the current tail direction.
|
||||||
* @return true if the line has been changed.
|
* @return true if the line has been changed.
|
||||||
*/
|
*/
|
||||||
|
@ -146,7 +146,7 @@ private:
|
||||||
/**
|
/**
|
||||||
* Function mergeHead()
|
* Function mergeHead()
|
||||||
*
|
*
|
||||||
* Moves "estabished" segments from the head to the tail if certain
|
* Moves "estabished" segments from the head to the tail if certain
|
||||||
* conditions are met.
|
* conditions are met.
|
||||||
* @return true, if the line has been changed.
|
* @return true, if the line has been changed.
|
||||||
*/
|
*/
|
||||||
|
@ -155,20 +155,20 @@ private:
|
||||||
/**
|
/**
|
||||||
* Function reduceTail()
|
* Function reduceTail()
|
||||||
*
|
*
|
||||||
* Attempts to reduce the numer of segments in the tail by trying to replace a
|
* Attempts to reduce the numer of segments in the tail by trying to replace a
|
||||||
* certain number of latest tail segments with a direct trace leading to aEnd
|
* certain number of latest tail segments with a direct trace leading to aEnd
|
||||||
* that does not collide with anything.
|
* that does not collide with anything.
|
||||||
* @param aEnd: current routing destination point.
|
* @param aEnd: current routing destination point.
|
||||||
* @return true if the line has been changed.
|
* @return true if the line has been changed.
|
||||||
*/
|
*/
|
||||||
bool reduceTail( const VECTOR2I& aEnd );
|
bool reduceTail( const VECTOR2I& aEnd );
|
||||||
|
|
||||||
void fixHeadPosture();
|
void fixHeadPosture();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function optimizeTailHeadTransition()
|
* Function optimizeTailHeadTransition()
|
||||||
*
|
*
|
||||||
* Tries to reduce the corner count of the most recent part of tail/head by
|
* Tries to reduce the corner count of the most recent part of tail/head by
|
||||||
* merging obtuse/collinear segments.
|
* merging obtuse/collinear segments.
|
||||||
* @return true, if the line has been changed.
|
* @return true, if the line has been changed.
|
||||||
*/
|
*/
|
||||||
|
@ -177,12 +177,12 @@ private:
|
||||||
/**
|
/**
|
||||||
* Function routeHead()
|
* Function routeHead()
|
||||||
*
|
*
|
||||||
* Computes the head trace between the current start point (m_p_start) and
|
* Computes the head trace between the current start point (m_p_start) and
|
||||||
* point aP, starting with direction defined in m_direction. The trace walks
|
* point aP, starting with direction defined in m_direction. The trace walks
|
||||||
* around all colliding solid or non-movable items. Movable segments are
|
* around all colliding solid or non-movable items. Movable segments are
|
||||||
* ignored, as they'll be handled later by the shove algorithm.
|
* ignored, as they'll be handled later by the shove algorithm.
|
||||||
*/
|
*/
|
||||||
bool routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead,
|
bool routeHead( const VECTOR2I& aP, PNS_LINE& aNewHead,
|
||||||
bool aCwWalkaround = true );
|
bool aCwWalkaround = true );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,7 +197,7 @@ private:
|
||||||
///> routing mode (walkaround, shove, etc.)
|
///> routing mode (walkaround, shove, etc.)
|
||||||
PNS_MODE m_mode;
|
PNS_MODE m_mode;
|
||||||
|
|
||||||
///> follow mouse trail by attaching new segments to the head
|
///> follow mouse trail by attaching new segments to the head
|
||||||
///> as the cursor moves
|
///> as the cursor moves
|
||||||
bool m_follow_mouse;
|
bool m_follow_mouse;
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ PNS_NODE::~PNS_NODE()
|
||||||
|
|
||||||
allocNodes.erase( this );
|
allocNodes.erase( this );
|
||||||
|
|
||||||
for( PNS_INDEX::ItemSet::iterator i = m_index->begin();
|
for( PNS_INDEX::ItemSet::iterator i = m_index->begin();
|
||||||
i != m_index->end(); ++i )
|
i != m_index->end(); ++i )
|
||||||
if( (*i)->BelongsTo( this ) )
|
if( (*i)->BelongsTo( this ) )
|
||||||
delete *i;
|
delete *i;
|
||||||
|
@ -111,14 +111,14 @@ PNS_NODE* PNS_NODE::Branch()
|
||||||
child->m_clearanceFunctor = m_clearanceFunctor;
|
child->m_clearanceFunctor = m_clearanceFunctor;
|
||||||
child->m_root = isRoot() ? this : m_root;
|
child->m_root = isRoot() ? this : m_root;
|
||||||
|
|
||||||
// immmediate offspring of the root branch needs not copy anything.
|
// immmediate offspring of the root branch needs not copy anything.
|
||||||
// For the rest, deep-copy joints, overridden item map and pointers
|
// For the rest, deep-copy joints, overridden item map and pointers
|
||||||
// to stored items.
|
// to stored items.
|
||||||
if( !isRoot() )
|
if( !isRoot() )
|
||||||
{
|
{
|
||||||
JointMap::iterator j;
|
JointMap::iterator j;
|
||||||
|
|
||||||
for( PNS_INDEX::ItemSet::iterator i = m_index->begin();
|
for( PNS_INDEX::ItemSet::iterator i = m_index->begin();
|
||||||
i != m_index->end(); ++i )
|
i != m_index->end(); ++i )
|
||||||
child->m_index->Add( *i );
|
child->m_index->Add( *i );
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ void PNS_NODE::unlinkParent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// function object that visits potential obstacles and performs
|
// function object that visits potential obstacles and performs
|
||||||
// the actual collision refining
|
// the actual collision refining
|
||||||
struct PNS_NODE::obstacleVisitor
|
struct PNS_NODE::obstacleVisitor
|
||||||
{
|
{
|
||||||
|
@ -200,7 +200,7 @@ struct PNS_NODE::obstacleVisitor
|
||||||
if( !aItem->OfKind( m_kindMask ) )
|
if( !aItem->OfKind( m_kindMask ) )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// check if there is a more recent branch with a newer
|
// check if there is a more recent branch with a newer
|
||||||
// (possibily modified) version of this item.
|
// (possibily modified) version of this item.
|
||||||
if( m_override && m_override->overrides( aItem ) )
|
if( m_override && m_override->overrides( aItem ) )
|
||||||
return true;
|
return true;
|
||||||
|
@ -428,8 +428,8 @@ struct hitVisitor
|
||||||
const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint )
|
const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint )
|
||||||
{
|
{
|
||||||
PNS_ITEMSET items;
|
PNS_ITEMSET items;
|
||||||
// fixme: we treat a point as an infinitely small circle - this is inefficient.
|
// fixme: we treat a point as an infinitely small circle - this is inefficient.
|
||||||
SHAPE_CIRCLE s( aPoint, 0 );
|
SHAPE_CIRCLE s( aPoint, 0 );
|
||||||
hitVisitor visitor( items, aPoint, this );
|
hitVisitor visitor( items, aPoint, this );
|
||||||
|
|
||||||
m_index->Query( &s, m_maxClearance, visitor );
|
m_index->Query( &s, m_maxClearance, visitor );
|
||||||
|
@ -537,12 +537,12 @@ void PNS_NODE::Add( PNS_ITEM* aItem )
|
||||||
|
|
||||||
void PNS_NODE::doRemove( PNS_ITEM* aItem )
|
void PNS_NODE::doRemove( PNS_ITEM* aItem )
|
||||||
{
|
{
|
||||||
// case 1: removing an item that is stored in the root node from any branch:
|
// case 1: removing an item that is stored in the root node from any branch:
|
||||||
// mark it as overridden, but do not remove
|
// mark it as overridden, but do not remove
|
||||||
if( aItem->BelongsTo( m_root ) && !isRoot() )
|
if( aItem->BelongsTo( m_root ) && !isRoot() )
|
||||||
m_override.insert( aItem );
|
m_override.insert( aItem );
|
||||||
|
|
||||||
// case 2: the item belongs to this branch or a parent, non-root branch,
|
// case 2: the item belongs to this branch or a parent, non-root branch,
|
||||||
// or the root itself and we are the root: remove from the index
|
// or the root itself and we are the root: remove from the index
|
||||||
else if( !aItem->BelongsTo( m_root ) || isRoot() )
|
else if( !aItem->BelongsTo( m_root ) || isRoot() )
|
||||||
m_index->Remove( aItem );
|
m_index->Remove( aItem );
|
||||||
|
@ -948,7 +948,7 @@ void PNS_NODE::Commit( PNS_NODE* aNode )
|
||||||
BOOST_FOREACH( PNS_ITEM * item, aNode->m_override )
|
BOOST_FOREACH( PNS_ITEM * item, aNode->m_override )
|
||||||
Remove( item );
|
Remove( item );
|
||||||
|
|
||||||
for( PNS_INDEX::ItemSet::iterator i = aNode->m_index->begin();
|
for( PNS_INDEX::ItemSet::iterator i = aNode->m_index->begin();
|
||||||
i != aNode->m_index->end(); ++i )
|
i != aNode->m_index->end(); ++i )
|
||||||
Add( *i );
|
Add( *i );
|
||||||
|
|
||||||
|
|
|
@ -79,13 +79,13 @@ struct PNS_OBSTACLE
|
||||||
/**
|
/**
|
||||||
* Class PNS_NODE
|
* Class PNS_NODE
|
||||||
*
|
*
|
||||||
* Keeps the router "world" - i.e. all the tracks, vias, solids in a
|
* Keeps the router "world" - i.e. all the tracks, vias, solids in a
|
||||||
* hierarchical and indexed way.
|
* hierarchical and indexed way.
|
||||||
* Features:
|
* Features:
|
||||||
* - spatial-indexed container for PCB item shapes
|
* - spatial-indexed container for PCB item shapes
|
||||||
* - collision search (with clearance checking)
|
* - collision search (with clearance checking)
|
||||||
* - assembly of lines connecting joints, finding loops and unique paths
|
* - assembly of lines connecting joints, finding loops and unique paths
|
||||||
* - lightweight cloning/branching (for recursive optimization and shove
|
* - lightweight cloning/branching (for recursive optimization and shove
|
||||||
* springback)
|
* springback)
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
@ -145,11 +145,11 @@ public:
|
||||||
void Remove( PNS_ITEM* aItem );
|
void Remove( PNS_ITEM* aItem );
|
||||||
void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem );
|
void Replace( PNS_ITEM* aOldItem, PNS_ITEM* aNewItem );
|
||||||
|
|
||||||
///> Creates a lightweight copy ("branch") of self. Note that if there are
|
///> Creates a lightweight copy ("branch") of self. Note that if there are
|
||||||
///> any branches in use, their parents must NOT be deleted.
|
///> any branches in use, their parents must NOT be deleted.
|
||||||
PNS_NODE* Branch();
|
PNS_NODE* Branch();
|
||||||
|
|
||||||
///> Assembles a line connecting two non-trivial joints the
|
///> Assembles a line connecting two non-trivial joints the
|
||||||
///> segment aSeg belongs to.
|
///> segment aSeg belongs to.
|
||||||
PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg,
|
PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg,
|
||||||
const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint() );
|
const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint() );
|
||||||
|
@ -175,15 +175,15 @@ public:
|
||||||
const OptJoint FindJoint( const VECTOR2I& aPos, int aLayer, int aNet );
|
const OptJoint FindJoint( const VECTOR2I& aPos, int aLayer, int aNet );
|
||||||
|
|
||||||
///> finds all linest between a pair of joints. Used by the loop removal engine.
|
///> finds all linest between a pair of joints. Used by the loop removal engine.
|
||||||
int FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b,
|
int FindLinesBetweenJoints( PNS_JOINT& a, PNS_JOINT& b,
|
||||||
std::vector<PNS_LINE*>& aLines );
|
std::vector<PNS_LINE*>& aLines );
|
||||||
|
|
||||||
///> finds the joints corresponding to the ends of line aLine
|
///> finds the joints corresponding to the ends of line aLine
|
||||||
void FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b );
|
void FindLineEnds( PNS_LINE* aLine, PNS_JOINT& a, PNS_JOINT& b );
|
||||||
|
|
||||||
///> finds all joints that have an (in)direct connection(s)
|
///> finds all joints that have an (in)direct connection(s)
|
||||||
///> (i.e. segments/vias) with the joint aJoint.
|
///> (i.e. segments/vias) with the joint aJoint.
|
||||||
void FindConnectedJoints( const PNS_JOINT& aJoint,
|
void FindConnectedJoints( const PNS_JOINT& aJoint,
|
||||||
std::vector<PNS_JOINT*>& aConnectedJoints );
|
std::vector<PNS_JOINT*>& aConnectedJoints );
|
||||||
|
|
||||||
///> Destroys all child nodes. Applicable only to the root node.
|
///> Destroys all child nodes. Applicable only to the root node.
|
||||||
|
@ -201,15 +201,15 @@ private:
|
||||||
PNS_NODE& operator=( const PNS_NODE& b );
|
PNS_NODE& operator=( const PNS_NODE& b );
|
||||||
|
|
||||||
///> tries to find matching joint and creates a new one if not found
|
///> tries to find matching joint and creates a new one if not found
|
||||||
PNS_JOINT& touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
PNS_JOINT& touchJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
||||||
int aNet );
|
int aNet );
|
||||||
|
|
||||||
///> touches a joint and links it to an item
|
///> touches a joint and links it to an item
|
||||||
void linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
void linkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
||||||
int aNet, PNS_ITEM* aWhere );
|
int aNet, PNS_ITEM* aWhere );
|
||||||
|
|
||||||
///> unlinks an item from a joint
|
///> unlinks an item from a joint
|
||||||
void unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
void unlinkJoint( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
|
||||||
int aNet, PNS_ITEM* aWhere );
|
int aNet, PNS_ITEM* aWhere );
|
||||||
|
|
||||||
///> helpers for adding/removing items
|
///> helpers for adding/removing items
|
||||||
|
@ -231,7 +231,7 @@ private:
|
||||||
return m_parent == NULL;
|
return m_parent == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
///> checks if this branch contains an updated version of the item
|
///> checks if this branch contains an updated version of the item
|
||||||
///> from the root branch.
|
///> from the root branch.
|
||||||
bool overrides( PNS_ITEM* aItem ) const
|
bool overrides( PNS_ITEM* aItem ) const
|
||||||
{
|
{
|
||||||
|
@ -249,7 +249,7 @@ private:
|
||||||
///> spatial index of all items
|
///> spatial index of all items
|
||||||
// SHAPE_INDEX_LIST<PNS_ITEM *> m_items;
|
// SHAPE_INDEX_LIST<PNS_ITEM *> m_items;
|
||||||
|
|
||||||
///> hash table with the joints, linking the items. Joints are hashed by
|
///> hash table with the joints, linking the items. Joints are hashed by
|
||||||
///> their position, layer set and net.
|
///> their position, layer set and net.
|
||||||
JointMap m_joints;
|
JointMap m_joints;
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther,
|
||||||
{
|
{
|
||||||
if( aOther.m_cornerCost < m_cornerCost && aOther.m_lengthCost < m_lengthCost )
|
if( aOther.m_cornerCost < m_cornerCost && aOther.m_lengthCost < m_lengthCost )
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
else if( aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost <
|
else if( aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost <
|
||||||
m_lengthCost * aLengthTollerance )
|
m_lengthCost * aLengthTollerance )
|
||||||
return true;
|
return true;
|
||||||
|
@ -531,19 +531,19 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth,
|
||||||
|
|
||||||
if( s.x >= s.y )
|
if( s.x >= s.y )
|
||||||
{
|
{
|
||||||
breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset,
|
breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset,
|
||||||
c + d_offset + VECTOR2I( l, l ) ) );
|
c + d_offset + VECTOR2I( l, l ) ) );
|
||||||
breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset,
|
breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset,
|
||||||
c + d_offset - VECTOR2I( -l, l ) ) );
|
c + d_offset - VECTOR2I( -l, l ) ) );
|
||||||
breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset,
|
breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset,
|
||||||
c - d_offset + VECTOR2I( -l, l ) ) );
|
c - d_offset + VECTOR2I( -l, l ) ) );
|
||||||
breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset,
|
breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset,
|
||||||
c - d_offset - VECTOR2I( l, l ) ) );
|
c - d_offset - VECTOR2I( l, l ) ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// fixme: this could be done more efficiently
|
// fixme: this could be done more efficiently
|
||||||
breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset,
|
breakouts.push_back( SHAPE_LINE_CHAIN( c, c + d_offset,
|
||||||
c + d_offset + VECTOR2I( l, l ) ) );
|
c + d_offset + VECTOR2I( l, l ) ) );
|
||||||
breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset,
|
breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset,
|
||||||
c - d_offset - VECTOR2I( -l, l ) ) );
|
c - d_offset - VECTOR2I( -l, l ) ) );
|
||||||
|
@ -640,7 +640,7 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd,
|
||||||
for( int diag = 0; diag < 2; diag++ )
|
for( int diag = 0; diag < 2; diag++ )
|
||||||
{
|
{
|
||||||
SHAPE_LINE_CHAIN v;
|
SHAPE_LINE_CHAIN v;
|
||||||
SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint( -1 ),
|
SHAPE_LINE_CHAIN connect = dir.BuildInitialTrace( l.CPoint( -1 ),
|
||||||
line.CPoint( p ), diag == 0 );
|
line.CPoint( p ), diag == 0 );
|
||||||
|
|
||||||
DIRECTION_45 dir_bkout( l.CSegment( -1 ) );
|
DIRECTION_45 dir_bkout( l.CSegment( -1 ) );
|
||||||
|
@ -691,7 +691,7 @@ int PNS_OPTIMIZER::smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd,
|
||||||
|
|
||||||
if( !checkColliding( &tmp ) )
|
if( !checkColliding( &tmp ) )
|
||||||
{
|
{
|
||||||
/* if(aEnd)
|
/* if(aEnd)
|
||||||
* PNSDisplayDebugLine (l_best, 6);
|
* PNSDisplayDebugLine (l_best, 6);
|
||||||
* else
|
* else
|
||||||
* PNSDisplayDebugLine (l_best, 5);*/
|
* PNSDisplayDebugLine (l_best, 5);*/
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
// an ugly singleton for drawing debug items within the router context.
|
// an ugly singleton for drawing debug items within the router context.
|
||||||
// To be fixed sometime in the future.
|
// To be fixed sometime in the future.
|
||||||
static PNS_ROUTER* theRouter;
|
static PNS_ROUTER* theRouter;
|
||||||
|
|
||||||
|
|
|
@ -429,7 +429,7 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines( PNS_LINE* aCurrentHead )
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if(lastWalkSolid == nearest->item)
|
/* if(lastWalkSolid == nearest->item)
|
||||||
* {
|
* {
|
||||||
* fail = true;
|
* fail = true;
|
||||||
* break;
|
* break;
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
private:
|
private:
|
||||||
static const int ShoveTimeLimit = 3000;
|
static const int ShoveTimeLimit = 3000;
|
||||||
|
|
||||||
bool tryShove( PNS_NODE* aWorld, PNS_LINE* aTrack, PNS_LINE* aObstacle,
|
bool tryShove( PNS_NODE* aWorld, PNS_LINE* aTrack, PNS_LINE* aObstacle,
|
||||||
PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult, bool aInvertWinding );
|
PNS_SEGMENT& aObstacleSeg, PNS_LINE* aResult, bool aInvertWinding );
|
||||||
|
|
||||||
ShoveStatus shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, PNS_LINE* aObstacle,
|
ShoveStatus shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, PNS_LINE* aObstacle,
|
||||||
|
|
|
@ -74,7 +74,7 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::singleStep( PNS_LINE& aPath,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aPath.NewWalkaround( current_obs->hull, path_pre[0], path_walk[0],
|
aPath.NewWalkaround( current_obs->hull, path_pre[0], path_walk[0],
|
||||||
path_post[0], aWindingDirection );
|
path_post[0], aWindingDirection );
|
||||||
aPath.NewWalkaround( current_obs->hull, path_pre[1], path_walk[1],
|
aPath.NewWalkaround( current_obs->hull, path_pre[1], path_walk[1],
|
||||||
path_post[1], !aWindingDirection );
|
path_post[1], !aWindingDirection );
|
||||||
|
|
|
@ -72,7 +72,7 @@ public:
|
||||||
m_cursorApproachMode = aEnabled;
|
m_cursorApproachMode = aEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath,
|
WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath,
|
||||||
bool aOptimize = true );
|
bool aOptimize = true );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -100,7 +100,7 @@ int ROUTER_TOOL::getDefaultWidth( int aNetCode )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth,
|
void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth,
|
||||||
int& aViaDiameter, int& aViaDrill )
|
int& aViaDiameter, int& aViaDrill )
|
||||||
{
|
{
|
||||||
BOARD* board = getModel<BOARD>( PCB_T );
|
BOARD* board = getModel<BOARD>( PCB_T );
|
||||||
|
|
Loading…
Reference in New Issue