Converted tabs to spaces. Removed trailing whitespaces.

This commit is contained in:
Maciej Suminski 2013-10-14 13:43:57 +02:00
parent ac489ece7b
commit 22045b61ea
55 changed files with 2739 additions and 2740 deletions

View File

@ -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 );
} }

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View File

@ -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 );
} }

View File

@ -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 );
} }

View File

@ -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();
} }

View File

@ -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__

View File

@ -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

View File

@ -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();
} }

View File

@ -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();
} }

View File

@ -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 );
} }

View File

@ -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;
} }

View File

@ -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 );
} }

View File

@ -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();
} }
} }

View File

@ -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.

View File

@ -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.

View File

@ -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

View 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;
} }

View File

@ -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;
}; };

View File

@ -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

View File

@ -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 );
} }
/** /**

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

0
pcbnew/edit.cpp Executable file → Normal file
View File

View File

@ -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 );

View File

@ -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.
**/ **/

View File

@ -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;

View File

@ -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 )

View File

@ -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

View File

@ -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))

View File

@ -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;

View File

@ -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 );

View File

@ -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;

View File

@ -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);*/

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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 );

View File

@ -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:

View File

@ -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 );