Commit 22045b61 authored by Maciej Suminski's avatar Maciej Suminski

Converted tabs to spaces. Removed trailing whitespaces.

parent ac489ece
......@@ -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 );
/* Generic events for the Tool Dispatcher */
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_DOWN, 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_MIDDLE_UP, 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_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) );
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_MOTION, 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_RIGHT_UP, 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_DOWN, 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_KEY_UP, 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( KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE,
wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
m_refreshTimer.SetOwner( 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_pendingRefresh = true;
}
}
}
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 )
{
if( !m_eventDispatcher )
{
aEvent.Skip();
return;
}
else
{
if( !m_eventDispatcher )
{
aEvent.Skip();
return;
}
else
{
m_eventDispatcher->DispatchWxEvent( aEvent );
}
......
......@@ -159,7 +159,6 @@ void COLOR4D::FromHSV( double aInH, double aInS, double aInV )
b = q;
break;
}
}
......@@ -168,7 +167,7 @@ COLOR4D& COLOR4D::Saturate( double aFactor )
double h, s, v;
ToHSV( h, s, v );
FromHSV( h, aFactor, 1.0 );
return *this;
}
......@@ -127,7 +127,7 @@ void OPENGL_GAL::BeginDrawing()
glViewport( 0, 0, (GLsizei) screenSize.x, (GLsizei) screenSize.y );
// 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 );
// Prepare rendering target buffers
......
......@@ -49,7 +49,7 @@ void strokedCircle( vec2 aCoord, float aRadius, float aWidth )
float innerRadius = aRadius - ( aWidth / 2 );
float relWidth = innerRadius / outerRadius;
if( ( dot( aCoord, aCoord ) < 1.0f ) &&
if( ( dot( aCoord, aCoord ) < 1.0f ) &&
( dot( aCoord, aCoord ) > relWidth * relWidth ) )
gl_FragColor = gl_Color;
else
......
......@@ -42,23 +42,23 @@ void main()
{
// Pass attributes to the fragment shader
shaderParams = attrShaderParams;
if( shaderParams[0] == SHADER_LINE )
{
float lineWidth = shaderParams[3];
float worldScale = gl_ModelViewMatrix[0][0];
float scale;
// Make lines appear to be at least 1 pixel wide
if( worldScale * lineWidth < MIN_WIDTH )
scale = MIN_WIDTH / ( worldScale * lineWidth );
else
scale = 1.0f;
gl_Position = gl_ModelViewProjectionMatrix *
gl_Position = gl_ModelViewProjectionMatrix *
( 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 ) )
{
// Compute relative circle coordinates basing on indices
......@@ -69,7 +69,7 @@ void main()
circleCoords = vec2( sqrt( 3.0f ), -1.0f );
else if( shaderParams[1] == 3.0f )
circleCoords = vec2( 0.0f, 2.0f );
// Semicircle
else if( shaderParams[1] == 4.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
float lineWidth = shaderParams[3];
float worldScale = gl_ModelViewMatrix[0][0];
// Make lines appear to be at least 1 pixel width
if( worldScale * lineWidth < MIN_WIDTH )
shaderParams[3] = shaderParams[3] / ( worldScale * lineWidth );
......@@ -93,7 +93,7 @@ void main()
// Pass through the coordinates like in the fixed pipeline
gl_Position = ftransform();
}
gl_FrontColor = gl_Color;
}
......@@ -32,38 +32,38 @@ template<typename T> int sgn( T val ) {
bool SEG::PointCloserThan( const VECTOR2I& aP, int dist ) const
{
VECTOR2I d = b - a;
ecoord dist_sq = (ecoord) dist * dist;
VECTOR2I d = b - a;
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 );
if( t <= 0 || !l_squared )
return ( aP - a ).SquaredEuclideanNorm() < dist_sq;
else if( t >= l_squared )
return ( aP - b ).SquaredEuclideanNorm() < dist_sq;
return ( aP - a ).SquaredEuclideanNorm() < dist_sq;
else if( t >= l_squared )
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 )
{
int ca = -sgn( d.y );
int cb = sgn( d.x );
int cc = -ca * a.x - cb * a.y;
ecoord num = ca * aP.x + cb * aP.y + cc;
num *= num;
if( ca && cb )
num >>= 1;
if( num > ( dist_sq + 100 ) )
return false;
else if( num < ( dist_sq - 100 ) )
return true;
int ca = -sgn( d.y );
int cb = sgn( d.x );
int cc = -ca * a.x - cb * a.y;
ecoord num = ca * aP.x + cb * aP.y + cc;
num *= num;
if( ca && cb )
num >>= 1;
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.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....
if( Intersect( aSeg ) )
......@@ -91,62 +91,62 @@ SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
return m;
}
OPT_VECTOR2I SEG::Intersect( const SEG& aSeg, bool aIgnoreEndpoints, bool aLines ) const
{
const VECTOR2I e ( b - a );
const VECTOR2I f ( aSeg.b - aSeg.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;
const VECTOR2I e ( b - a );
const VECTOR2I f ( aSeg.b - aSeg.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;
}
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
// fixme: move to a method
if( ccw( a, aSeg.a, aSeg.b ) != ccw( b, aSeg.a, aSeg.b ) &&
ccw( a, b, aSeg.a ) != ccw( a, b, aSeg.b ) )
return true;
// check for intersection
// fixme: move to a method
if( ccw( a, aSeg.a, aSeg.b ) != ccw( b, aSeg.a, aSeg.b ) &&
ccw( a, b, aSeg.a ) != ccw( a, b, aSeg.b ) )
return true;
#define CHK(_seg, _pt) \
if( (_seg).PointCloserThan (_pt, aClearance ) ) return true;
CHK( *this, aSeg.a );
CHK( *this, aSeg.b );
CHK( aSeg, a );
CHK( aSeg, b );
if( (_seg).PointCloserThan (_pt, aClearance ) ) return true;
CHK( *this, aSeg.a );
CHK( *this, aSeg.b );
CHK( aSeg, a );
CHK( aSeg, b );
#undef CHK
return false;
return false;
}
bool SEG::Contains( const VECTOR2I& aP ) const
{
return PointCloserThan( aP, 1 );
return PointCloserThan( aP, 1 );
}
......@@ -34,200 +34,200 @@ typedef VECTOR2I::extended_type ecoord;
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CIRCLE& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
ecoord min_dist_sq = min_dist * min_dist;
const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
ecoord min_dist = aClearance + aA.GetRadius() + aB.GetRadius();
ecoord min_dist_sq = min_dist * min_dist;
ecoord dist_sq = delta.SquaredEuclideanNorm();
const VECTOR2I delta = aB.GetCenter() - aA.GetCenter();
if ( dist_sq >= min_dist_sq )
return false;
if ( aNeedMTV )
aMTV = delta.Resize( sqrt ( abs( min_dist_sq - dist_sq ) ) + 1 );
ecoord dist_sq = delta.SquaredEuclideanNorm();
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,
bool aNeedMTV, VECTOR2I& aMTV )
{
const VECTOR2I c = aB.GetCenter();
const VECTOR2I p0 = aA.GetPosition();
const VECTOR2I size = aA.GetSize();
const ecoord r = aB.GetRadius();
const ecoord min_dist = aClearance + r;
const ecoord min_dist_sq = min_dist * min_dist;
if ( aA.BBox( 0 ).Contains( c ) )
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;
VECTOR2I nearest;
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
if( !inside )
{
for( int i = 0; i < 4; i++ )
{
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 )
return false;
VECTOR2I delta = c - nearest;
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;
const VECTOR2I c = aB.GetCenter();
const VECTOR2I p0 = aA.GetPosition();
const VECTOR2I size = aA.GetSize();
const ecoord r = aB.GetRadius();
const ecoord min_dist = aClearance + r;
const ecoord min_dist_sq = min_dist * min_dist;
if ( aA.BBox( 0 ).Contains( c ) )
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;
VECTOR2I nearest;
bool inside = c.x >= p0.x && c.x <= ( p0.x + size.x )
&& c.y >= p0.y && c.y <= ( p0.y + size.y );
if( !inside )
{
for( int i = 0; i < 4; i++ )
{
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 )
return false;
VECTOR2I delta = c - nearest;
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,
bool aNeedMTV, VECTOR2I& aMTV )
{
for( int s = 0; s < aB.SegmentCount(); s++ )
{
if ( aA.Collide( aB.CSegment( s ), aClearance ) )
return true;
}
return false;
for( int s = 0; s < aB.SegmentCount(); s++ )
{
if ( aA.Collide( aB.CSegment( s ), aClearance ) )
return true;
}
return false;
}
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
for( int i = 0; i < aB.SegmentCount(); i++ )
if( aA.Collide( aB.CSegment(i), aClearance ) )
return true;
return false;
for( int i = 0; i < aB.SegmentCount(); i++ )
if( aA.Collide( aB.CSegment(i), aClearance ) )
return true;
return false;
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
for( int s = 0; s < aB.SegmentCount(); s++ )
{
SEG seg = aB.CSegment( s );
if( aA.Collide( seg, aClearance ) )
return true;
}
return false;
for( int s = 0; s < aB.SegmentCount(); s++ )
{
SEG seg = aB.CSegment( s );
if( aA.Collide( seg, aClearance ) )
return true;
}
return false;
}
bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
{
switch( aA->Type() )
{
case SH_RECT:
switch( aB->Type() )
{
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
case SH_CIRCLE:
switch( aB->Type() )
{
case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_CIRCLE*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN *>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
case SH_LINE_CHAIN:
switch( aB->Type() )
{
case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
default:
break;
}
bool unsupported_collision = true;
assert( unsupported_collision == false );
return false;
switch( aA->Type() )
{
case SH_RECT:
switch( aB->Type() )
{
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_RECT*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
case SH_CIRCLE:
switch( aB->Type() )
{
case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_CIRCLE*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_CIRCLE*>( aB ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN *>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
case SH_LINE_CHAIN:
switch( aB->Type() )
{
case SH_RECT:
return Collide( *static_cast<const SHAPE_RECT*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_CIRCLE:
return Collide( *static_cast<const SHAPE_CIRCLE*>( aB ),
*static_cast<const SHAPE_LINE_CHAIN*>( aA ), aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return Collide( *static_cast<const SHAPE_LINE_CHAIN*>( aA ),
*static_cast<const SHAPE_LINE_CHAIN*>( aB ), aClearance, aNeedMTV, aMTV );
default:
break;
}
default:
break;
}
bool unsupported_collision = true;
assert( unsupported_collision == false );
return false;
}
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
{
VECTOR2I dummy;
return CollideShapes( this, aShape, aClerance, false, dummy );
VECTOR2I dummy;
return CollideShapes( this, aShape, aClerance, false, dummy );
}
......@@ -30,491 +30,491 @@ using boost::optional;
bool SHAPE_LINE_CHAIN::Collide( const VECTOR2I& aP, int aClearance ) const
{
assert( false );
return false;
assert( false );
return false;
}
bool SHAPE_LINE_CHAIN::Collide( const BOX2I& aBox, int aClearance ) const
{
assert( false );
return false;
assert( false );
return false;
}
bool SHAPE_LINE_CHAIN::Collide( const SEG& aSeg, int aClearance ) const
{
BOX2I box_a( aSeg.a, aSeg.b - aSeg.a );
BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
for( int i = 0; i < SegmentCount() ;i++ )
{
const SEG& s = CSegment( i );
BOX2I box_b( s.a, s.b - s.a );
BOX2I::ecoord_type d = box_a.SquaredDistance ( box_b );
if( d < dist_sq )
{
if( s.Collide( aSeg, aClearance ) )
return true;
}
}
return false;
BOX2I box_a( aSeg.a, aSeg.b - aSeg.a );
BOX2I::ecoord_type dist_sq = (BOX2I::ecoord_type) aClearance * aClearance;
for( int i = 0; i < SegmentCount() ;i++ )
{
const SEG& s = CSegment( i );
BOX2I box_b( s.a, s.b - s.a );
BOX2I::ecoord_type d = box_a.SquaredDistance ( box_b );
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 );
reverse( a.m_points.begin(), a.m_points.end() );
a.m_closed = m_closed;
SHAPE_LINE_CHAIN a( *this );
reverse( a.m_points.begin(), a.m_points.end() );
a.m_closed = m_closed;
return a;
return a;
}
int SHAPE_LINE_CHAIN::Length() const
{
int l = 0;
for( int i = 0; i < SegmentCount(); i++ )
l += CSegment( i ).Length();
int l = 0;
for( int i = 0; i < SegmentCount(); i++ )
l += CSegment( i ).Length();
return l;
return l;
}
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I& aP )
{
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
if( aStartIndex == aEndIndex )
m_points [aStartIndex] = aP;
else
{
m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 );
m_points[aStartIndex] = aP;
}
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
if( aStartIndex == aEndIndex )
m_points [aStartIndex] = aP;
else
{
m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 );
m_points[aStartIndex] = aP;
}
}
void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE_CHAIN& aLine )
{
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
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.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() );
}
void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
{
if(aEndIndex < 0)
aEndIndex += PointCount();
if(aStartIndex < 0)
aStartIndex += PointCount();
if(aEndIndex < 0)
aEndIndex += PointCount();
if(aStartIndex < 0)
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 d = INT_MAX;
for( int s = 0; s < SegmentCount(); s++ )
d = min( d, CSegment( s ).Distance( aP ) );
int d = INT_MAX;
for( int s = 0; s < SegmentCount(); s++ )
d = min( d, CSegment( s ).Distance( aP ) );
return d;
return d;
}
int SHAPE_LINE_CHAIN::Split( const VECTOR2I& aP )
{
int ii = -1;
int min_dist = 2;
ii = Find( aP );
if( ii >= 0 )
return ii;
for( int s = 0; s < SegmentCount(); s++ )
{
const SEG seg = CSegment( s );
int dist = seg.Distance( aP );
// 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( dist < min_dist && seg.a != aP && seg.b != aP )
{
min_dist = dist;
ii = s;
}
}
int ii = -1;
int min_dist = 2;
ii = Find( aP );
if( ii >= 0 )
return ii;
for( int s = 0; s < SegmentCount(); s++ )
{
const SEG seg = CSegment( s );
int dist = seg.Distance( aP );
// 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( dist < min_dist && seg.a != aP && seg.b != aP )
{
min_dist = dist;
ii = s;
}
}
if( ii >= 0 )
{
m_points.insert( m_points.begin() + ii + 1, aP );
if( ii >= 0 )
{
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
{
for( int s = 0; s< PointCount(); s++ )
if( CPoint( s ) == aP )
return s;
for( int s = 0; s< PointCount(); s++ )
if( CPoint( s ) == aP )
return s;
return -1;
return -1;
}
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex ) const
{
SHAPE_LINE_CHAIN rv;
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
SHAPE_LINE_CHAIN rv;
if( aEndIndex < 0 )
aEndIndex += PointCount();
if( aStartIndex < 0 )
aStartIndex += PointCount();
for( int i = aStartIndex; i <= aEndIndex; i++ )
rv.Append( m_points[i] );
for( int i = aStartIndex; i <= aEndIndex; i++ )
rv.Append( m_points[i] );
return rv;
return rv;
}
struct compareOriginDistance
{
compareOriginDistance( VECTOR2I& aOrigin ):
m_origin( aOrigin ) {};
compareOriginDistance( VECTOR2I& aOrigin ):
m_origin( aOrigin ) {};
bool operator()( const SHAPE_LINE_CHAIN::Intersection& aA,
const SHAPE_LINE_CHAIN::Intersection& aB )
{
return ( m_origin - aA.p ).EuclideanNorm() < ( m_origin - aB.p ).EuclideanNorm();
}
bool operator()( const SHAPE_LINE_CHAIN::Intersection& aA,
const SHAPE_LINE_CHAIN::Intersection& aB )
{
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
{
for( int s = 0; s < SegmentCount(); s++ )
{
OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg );
if( p )
{
Intersection is;
is.our = CSegment( s );
is.their = aSeg;
is.p = *p;
aIp.push_back( is );
}
}
compareOriginDistance comp( aSeg.a );
sort( aIp.begin(), aIp.end(), comp );
return aIp.size();
for( int s = 0; s < SegmentCount(); s++ )
{
OPT_VECTOR2I p = CSegment( s ).Intersect( aSeg );
if( p )
{
Intersection is;
is.our = CSegment( s );
is.their = aSeg;
is.p = *p;
aIp.push_back( is );
}
}
compareOriginDistance comp( aSeg.a );
sort( aIp.begin(), aIp.end(), comp );
return aIp.size();
}
int SHAPE_LINE_CHAIN::Intersect( const SHAPE_LINE_CHAIN& aChain, Intersections& aIp ) const
{
BOX2I bb_other = aChain.BBox();
for ( int s1 = 0; s1 < SegmentCount(); s1++ )
{
const SEG& a = CSegment( s1 );
const BOX2I bb_cur( a.a, a.b - a.a );
if( !bb_other.Intersects( bb_cur ) )
continue;
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
{
const SEG& b = aChain.CSegment( s2 );
Intersection is;
if( a.Collinear( b ) )
{
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++ )
{
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();
for ( int s1 = 0; s1 < SegmentCount(); s1++ )
{
const SEG& a = CSegment( s1 );
const BOX2I bb_cur( a.a, a.b - a.a );
if( !bb_other.Intersects( bb_cur ) )
continue;
for( int s2 = 0; s2 < aChain.SegmentCount(); s2++ )
{
const SEG& b = aChain.CSegment( s2 );
Intersection is;
if( a.Collinear( b ) )
{
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++ )
{
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 sum = 0;
for( int i = 0; i < SegmentCount(); i++ )
{
const SEG seg = CSegment( i );
int d = seg.Distance( aP );
if( d <= 1 )
{
sum += ( aP - seg.a ).EuclideanNorm();
return sum;
}
else
sum += seg.Length();
}
return -1;
int sum = 0;
for( int i = 0; i < SegmentCount(); i++ )
{
const SEG seg = CSegment( i );
int d = seg.Distance( aP );
if( d <= 1 )
{
sum += ( aP - seg.a ).EuclideanNorm();
return sum;
}
else
sum += seg.Length();
}
return -1;
}
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP ) const
{
if( !m_closed || SegmentCount() < 3 )
return false;
if( !m_closed || SegmentCount() < 3 )
return false;
int cur = CSegment(0).Side( aP );
int cur = CSegment(0).Side( aP );
if( cur == 0 )
return false;
if( cur == 0 )
return false;
for( int i = 1; i < SegmentCount(); i++ )
{
const SEG s = CSegment( i );
for( int i = 1; i < SegmentCount(); i++ )
{
const SEG s = CSegment( i );
if( aP == s.a || aP == s.b ) // edge does not belong to the interior!
return false;
if( aP == s.a || aP == s.b ) // edge does not belong to the interior!
return false;
if( s.Side(aP) != cur )
return false;
if( s.Side(aP) != cur )
return false;
}
return true;
return true;
}
bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP ) const
{
if( SegmentCount() < 1 )
return m_points[0] == aP;
if( SegmentCount() < 1 )
return m_points[0] == aP;
for( int i = 1; i < SegmentCount(); i++ )
{
const SEG s = CSegment( i );
if( s.a == aP || s.b == aP )
return true;
for( int i = 1; i < SegmentCount(); i++ )
{
const SEG s = CSegment( i );
if( s.Distance(aP) <= 1 )
return true;
}
if( s.a == aP || s.b == aP )
return true;
return false;
if( s.Distance(aP) <= 1 )
return true;
}
return false;
}
const optional<SHAPE_LINE_CHAIN::Intersection> SHAPE_LINE_CHAIN::SelfIntersecting() const
{
for( int s1 = 0; s1 < SegmentCount(); s1++ )
{
for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ )
{
const VECTOR2I s2a = CSegment( s2 ).a, s2b = CSegment( s2 ).b;
if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) )
{
Intersection is;
is.our = CSegment( s1 );
is.their = CSegment( s2 );
is.p = s2a;
return is;
}
else if( CSegment( s1 ).Contains(s2b ) )
{
Intersection is;
is.our = CSegment( s1 );
is.their = CSegment( s2 );
is.p = s2b;
return is;
}
else
{
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>();
for( int s1 = 0; s1 < SegmentCount(); s1++ )
{
for( int s2 = s1 + 1; s2 < SegmentCount(); s2++ )
{
const VECTOR2I s2a = CSegment( s2 ).a, s2b = CSegment( s2 ).b;
if( s1 + 1 != s2 && CSegment( s1 ).Contains( s2a ) )
{
Intersection is;
is.our = CSegment( s1 );
is.their = CSegment( s2 );
is.p = s2a;
return is;
}
else if( CSegment( s1 ).Contains(s2b ) )
{
Intersection is;
is.our = CSegment( s1 );
is.their = CSegment( s2 );
is.p = s2b;
return is;
}
else
{
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>();
}
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
{
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;
}
int i = 0;
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 ) );
i = j;
}
m_points.clear();
np = pts_unique.size();
i = 0;
// stage 1: eliminate collinear segments
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 )
n++;
m_points.push_back( p0 );
if( n > i )
i = n;
if( n == np )
{
m_points.push_back( pts_unique[n - 1] );
return *this;
}
i++;
}
if( np > 1 )
m_points.push_back( pts_unique[np - 2] );
m_points.push_back( pts_unique[np - 1] );
return *this;
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;
}
int i = 0;
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 ) );
i = j;
}
m_points.clear();
np = pts_unique.size();
i = 0;
// stage 1: eliminate collinear segments
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 )
n++;
m_points.push_back( p0 );
if( n > i )
i = n;
if( n == np )
{
m_points.push_back( pts_unique[n - 1] );
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
{
int min_d = INT_MAX;
int nearest = 0;
for ( int i = 0; i < SegmentCount(); i++ )
{
int d = CSegment( i ).Distance( aP );
if( d < min_d )
{
min_d = d;
nearest = i;
}
}
return CSegment( nearest ).NearestPoint( aP );
int min_d = INT_MAX;
int nearest = 0;
for ( int i = 0; i < SegmentCount(); i++ )
{
int d = CSegment( i ).Distance( aP );
if( d < min_d )
{
min_d = d;
nearest = i;
}
}
return CSegment( nearest ).NearestPoint( aP );
}
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++ )
ss << m_points[i].x << " " << m_points[i].y << " ";// Format() << " ";
for( int i = 0; i < PointCount(); i++ )
ss << m_points[i].x << " " << m_points[i].y << " ";// Format() << " ";
return ss.str();
return ss.str();
}
/*
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
does not support mingw */
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
does not support mingw */
#ifdef __APPLE__
......
......@@ -9,39 +9,39 @@
.align 2
_make_fcontext:
mov 0x4(%esp),%eax
lea -0x34(%eax),%eax
and $0xfffffff0,%eax
mov 0x4(%esp),%ecx
mov %ecx,0x18(%eax)
mov 0x8(%esp),%edx
mov %edx,0x1c(%eax)
neg %edx
lea (%edx,%ecx,1),%ecx
mov %ecx,0x20(%eax)
mov 0xc(%esp),%ecx
mov %ecx,0x14(%eax)
stmxcsr 0x2c(%eax)
fnstcw 0x30(%eax)
lea -0x1c(%eax),%edx
mov %edx,0x10(%eax)
mov $0x0,%ecx
mov %ecx,(%edx)
mov %fs:0x18,%ecx
mov (%ecx),%edx
inc %edx
je _make_fcontext+0x4c // <_make_fcontext+0x4c>
dec %edx
xchg %edx,%ecx
jmp _make_fcontext+0x42 // <_make_fcontext+0x42>
mov 0x4(%ecx),%ecx
mov 0x10(%eax),%edx
mov %ecx,0x18(%edx)
mov $0xffffffff,%ecx
mov %ecx,0x14(%edx)
lea 0x14(%edx),%ecx
mov %ecx,0x24(%eax)
ret
mov 0x4(%esp),%eax
lea -0x34(%eax),%eax
and $0xfffffff0,%eax
mov 0x4(%esp),%ecx
mov %ecx,0x18(%eax)
mov 0x8(%esp),%edx
mov %edx,0x1c(%eax)
neg %edx
lea (%edx,%ecx,1),%ecx
mov %ecx,0x20(%eax)
mov 0xc(%esp),%ecx
mov %ecx,0x14(%eax)
stmxcsr 0x2c(%eax)
fnstcw 0x30(%eax)
lea -0x1c(%eax),%edx
mov %edx,0x10(%eax)
mov $0x0,%ecx
mov %ecx,(%edx)
mov %fs:0x18,%ecx
mov (%ecx),%edx
inc %edx
je _make_fcontext+0x4c // <_make_fcontext+0x4c>
dec %edx
xchg %edx,%ecx
jmp _make_fcontext+0x42 // <_make_fcontext+0x42>
mov 0x4(%ecx),%ecx
mov 0x10(%eax),%edx
mov %ecx,0x18(%edx)
mov $0xffffffff,%ecx
mov %ecx,0x14(%edx)
lea 0x14(%edx),%ecx
mov %ecx,0x24(%eax)
ret
finish:
xor %eax,%eax
......
......@@ -31,14 +31,14 @@
CONTEXT_MENU::CONTEXT_MENU() :
m_titleSet( false ), m_handler( this ), m_tool( NULL )
{
m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
// Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu );
m_menu.AddPendingEvent( menuEvent );
m_menu.Connect( wxEVT_MENU_HIGHLIGHT, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
m_menu.Connect( wxEVT_COMMAND_MENU_SELECTED, wxEventHandler( CMEventHandler::onEvent ),
NULL, &m_handler );
// Workaround for the case when mouse cursor never reaches menu (it hangs up tools using menu)
wxMenuEvent menuEvent( wxEVT_MENU_HIGHLIGHT, -1, &m_menu );
m_menu.AddPendingEvent( menuEvent );
}
......@@ -72,16 +72,16 @@ void CONTEXT_MENU::SetTitle( const wxString& aTitle )
// TODO handle an empty string (remove title and separator)
// Unfortunately wxMenu::SetTitle() does nothing..
if( m_titleSet )
{
if( m_titleSet )
{
m_menu.FindItemByPosition( 0 )->SetItemLabel( aTitle );
}
else
{
}
else
{
m_menu.InsertSeparator( 0 );
m_menu.Insert( 0, new wxMenuItem( &m_menu, -1, aTitle, wxEmptyString, wxITEM_NORMAL ) );
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"
"undefined behaviour" ) );
#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() )
menuEntry = wxString( ( aAction.GetMenuItem() + '\t' + getHotKeyDescription( aAction ) ).c_str(),
wxConvUTF8 );
wxConvUTF8 );
else
menuEntry = wxString( aAction.GetMenuItem().c_str(), wxConvUTF8 );
......@@ -117,13 +117,13 @@ void CONTEXT_MENU::Add( const TOOL_ACTION& aAction )
void CONTEXT_MENU::Clear()
{
m_titleSet = false;
m_titleSet = false;
// Remove all the entries from context menu
for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i )
m_menu.Destroy( m_menu.FindItemByPosition( 0 ) );
// Remove all the entries from context menu
for( unsigned i = 0; i < m_menu.GetMenuItemCount(); ++i )
m_menu.Destroy( m_menu.FindItemByPosition( 0 ) );
m_toolActions.clear();
m_toolActions.clear();
}
......
......@@ -27,23 +27,23 @@
KiGfx::VIEW* TOOL_BASE::getView() const
{
return m_toolMgr->GetView();
return m_toolMgr->GetView();
}
KiGfx::VIEW_CONTROLS* TOOL_BASE::getViewControls() const
{
return m_toolMgr->GetViewControls();
{
return m_toolMgr->GetViewControls();
}
wxWindow* TOOL_BASE::getEditFrameInt() const
{
return m_toolMgr->GetEditFrame();
return m_toolMgr->GetEditFrame();
}
EDA_ITEM* TOOL_BASE::getModelInt() const
{
return m_toolMgr->GetModel();
return m_toolMgr->GetModel();
}
......@@ -42,52 +42,52 @@ using boost::optional;
///> Stores information about a mouse button state
struct TOOL_DISPATCHER::ButtonState
{
ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent,
const wxEventType& aUpEvent ) :
button( aButton ),
downEvent( aDownEvent ),
upEvent( aUpEvent )
{};
///> Flag indicating that dragging is active for the given button.
bool dragging;
///> Flag indicating that the given button is pressed.
bool pressed;
///> Point where dragging has started (in world coordinates).
VECTOR2D dragOrigin;
///> Point where click event has occurred.
VECTOR2D downPosition;
///> Difference between drag origin point and current mouse position (expressed as distance in
///> pixels).
double dragMaxDelta;
///> Determines the mouse button for which information are stored.
TOOL_MouseButtons button;
///> The type of wxEvent that determines mouse button press.
wxEventType downEvent;
///> The type of wxEvent that determines mouse button release.
wxEventType upEvent;
///> Time stamp for the last mouse button press event.
wxLongLong downTimestamp;
///> Restores initial state.
void Reset()
{
dragging = false;
pressed = false;
}
ButtonState( TOOL_MouseButtons aButton, const wxEventType& aDownEvent,
const wxEventType& aUpEvent ) :
button( aButton ),
downEvent( aDownEvent ),
upEvent( aUpEvent )
{};
///> Flag indicating that dragging is active for the given button.
bool dragging;
///> Flag indicating that the given button is pressed.
bool pressed;
///> Point where dragging has started (in world coordinates).
VECTOR2D dragOrigin;
///> Point where click event has occurred.
VECTOR2D downPosition;
///> Difference between drag origin point and current mouse position (expressed as distance in
///> pixels).
double dragMaxDelta;
///> Determines the mouse button for which information are stored.
TOOL_MouseButtons button;
///> The type of wxEvent that determines mouse button press.
wxEventType downEvent;
///> The type of wxEvent that determines mouse button release.
wxEventType upEvent;
///> Time stamp for the last mouse button press event.
wxLongLong downTimestamp;
///> Restores initial state.
void Reset()
{
dragging = false;
pressed = false;
}
};
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_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()
{
BOOST_FOREACH( ButtonState* st, m_buttons )
delete st;
BOOST_FOREACH( ButtonState* st, m_buttons )
delete st;
}
void TOOL_DISPATCHER::ResetState()
{
BOOST_FOREACH( ButtonState* st, m_buttons )
st->Reset();
BOOST_FOREACH( ButtonState* st, m_buttons )
st->Reset();
}
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 )
{
ButtonState* st = m_buttons[aIndex];
wxEventType type = aEvent.GetEventType();
optional<TOOL_EVENT> evt;
bool isClick = false;
bool up = type == st->upEvent;
bool down = type == st->downEvent;
int mods = decodeModifiers<wxMouseEvent>( static_cast<wxMouseEvent*>( &aEvent ) );
int args = st->button | mods;
if( down ) // Handle mouse button press
{
st->downTimestamp = wxGetLocalTimeMillis();
st->dragOrigin = m_lastMousePos;
st->downPosition = m_lastMousePos;
st->dragMaxDelta = 0;
st->pressed = true;
evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args );
}
else if( up ) // Handle mouse button release
{
st->pressed = false;
if( st->dragging )
{
wxLongLong t = wxGetLocalTimeMillis();
// Determine if it was just a single click or beginning of dragging
if( t - st->downTimestamp < DragTimeThreshold &&
st->dragMaxDelta < DragDistanceThreshold )
isClick = true;
else
evt = TOOL_EVENT( TC_Mouse, TA_MouseUp, args );
}
else
isClick = true;
if( isClick )
evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args );
st->dragging = false;
}
if( st->pressed && aMotion )
{
st->dragging = true;
double dragPixelDistance = getView()->ToScreen( m_lastMousePos - st->dragOrigin, false ).EuclideanNorm();
st->dragMaxDelta = std::max( st->dragMaxDelta, dragPixelDistance );
wxLongLong t = wxGetLocalTimeMillis();
if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold )
{
evt = TOOL_EVENT( TC_Mouse, TA_MouseDrag, args );
evt->SetMouseDragOrigin( st->dragOrigin );
evt->SetMouseDelta( m_lastMousePos - st->dragOrigin );
}
}
if( evt )
{
evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
m_toolMgr->ProcessEvent( *evt );
return true;
}
return false;
ButtonState* st = m_buttons[aIndex];
wxEventType type = aEvent.GetEventType();
optional<TOOL_EVENT> evt;
bool isClick = false;
bool up = type == st->upEvent;
bool down = type == st->downEvent;
int mods = decodeModifiers<wxMouseEvent>( static_cast<wxMouseEvent*>( &aEvent ) );
int args = st->button | mods;
if( down ) // Handle mouse button press
{
st->downTimestamp = wxGetLocalTimeMillis();
st->dragOrigin = m_lastMousePos;
st->downPosition = m_lastMousePos;
st->dragMaxDelta = 0;
st->pressed = true;
evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args );
}
else if( up ) // Handle mouse button release
{
st->pressed = false;
if( st->dragging )
{
wxLongLong t = wxGetLocalTimeMillis();
// Determine if it was just a single click or beginning of dragging
if( t - st->downTimestamp < DragTimeThreshold &&
st->dragMaxDelta < DragDistanceThreshold )
isClick = true;
else
evt = TOOL_EVENT( TC_Mouse, TA_MouseUp, args );
}
else
isClick = true;
if( isClick )
evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args );
st->dragging = false;
}
if( st->pressed && aMotion )
{
st->dragging = true;
double dragPixelDistance = getView()->ToScreen( m_lastMousePos - st->dragOrigin, false ).EuclideanNorm();
st->dragMaxDelta = std::max( st->dragMaxDelta, dragPixelDistance );
wxLongLong t = wxGetLocalTimeMillis();
if( t - st->downTimestamp > DragTimeThreshold || st->dragMaxDelta > DragDistanceThreshold )
{
evt = TOOL_EVENT( TC_Mouse, TA_MouseDrag, args );
evt->SetMouseDragOrigin( st->dragOrigin );
evt->SetMouseDelta( m_lastMousePos - st->dragOrigin );
}
}
if( evt )
{
evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
m_toolMgr->ProcessEvent( *evt );
return true;
}
return false;
}
void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
{
bool motion = false, buttonEvents = false;
optional<TOOL_EVENT> evt;
int type = aEvent.GetEventType();
// Mouse handling
if( type == wxEVT_MOTION || type == wxEVT_MOUSEWHEEL ||
type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP ||
// Event issued whem mouse retains position in screen coordinates,
// but changes in world coordinates (eg. autopanning)
type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
{
bool motion = false, buttonEvents = false;
optional<TOOL_EVENT> evt;
int type = aEvent.GetEventType();
// Mouse handling
if( type == wxEVT_MOTION || type == wxEVT_MOUSEWHEEL ||
type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_UP ||
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP ||
// 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 pos = getView()->ToWorld( screenPos );
if( pos != m_lastMousePos || type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
{
motion = true;
m_lastMousePos = pos;
}
if( pos != m_lastMousePos || type == KiGfx::WX_VIEW_CONTROLS::EVT_REFRESH_MOUSE )
{
motion = true;
m_lastMousePos = pos;
}
for( unsigned int i = 0; i < m_buttons.size(); i++ )
buttonEvents |= handleMouseButton( aEvent, i, motion );
for( unsigned int i = 0; i < m_buttons.size(); i++ )
buttonEvents |= handleMouseButton( aEvent, i, motion );
if( !buttonEvents && motion )
{
evt = TOOL_EVENT( TC_Mouse, TA_MouseMotion );
evt->SetMousePosition( pos );
}
}
if( !buttonEvents && motion )
{
evt = TOOL_EVENT( TC_Mouse, TA_MouseMotion );
evt->SetMousePosition( pos );
}
}
// Keyboard handling
else if( type == wxEVT_KEY_UP || type == wxEVT_KEY_DOWN )
// Keyboard handling
else if( type == wxEVT_KEY_UP || type == wxEVT_KEY_DOWN )
{
wxKeyEvent* ke = static_cast<wxKeyEvent*>( &aEvent );
int key = ke->GetKeyCode();
......@@ -246,33 +246,33 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
}
}
if( evt )
m_toolMgr->ProcessEvent( *evt );
if( evt )
m_toolMgr->ProcessEvent( *evt );
// pass the event to the GUI, it might still be interested in it
aEvent.Skip();
// pass the event to the GUI, it might still be interested in it
aEvent.Skip();
}
void TOOL_DISPATCHER::DispatchWxCommand( const wxCommandEvent& aEvent )
{
bool activateTool = false;
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
if( activateTool && m_editFrame->IsGalCanvasActive() )
m_toolMgr->InvokeTool( toolName );
bool activateTool = false;
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
if( activateTool && m_editFrame->IsGalCanvasActive() )
m_toolMgr->InvokeTool( toolName );
}
......@@ -35,22 +35,22 @@ using namespace std;
struct FlagString
{
int flag;
std::string str;
int flag;
std::string str;
};
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++ )
{
if( exps[i].flag & flag )
rv += exps[i].str + " ";
}
for( int i = 0; exps[i].str.length(); i++ )
{
if( exps[i].flag & flag )
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
{
std::string ev;
const FlagString categories[] = {
{ TC_Mouse, "mouse" },
{ TC_Keyboard, "keyboard" },
{ TC_Command, "command" },
{ TC_Message, "message" },
{ TC_View, "view" },
{ 0, "" }
};
const FlagString actions[] = {
{ TA_MouseClick, "click" },
{ TA_MouseUp, "button-up" },
{ TA_MouseDown, "button-down" },
{ TA_MouseDrag, "drag" },
{ TA_MouseMotion, "motion" },
{ TA_MouseWheel, "wheel" },
{ TA_KeyUp, "key-up" },
{ TA_KeyDown, "key-down" },
{ TA_ViewRefresh, "view-refresh" },
{ TA_ViewZoom, "view-zoom" },
{ TA_ViewPan, "view-pan" },
{ TA_ViewDirty, "view-dirty" },
{ TA_ChangeLayer, "change-layer" },
{ TA_CancelTool, "cancel-tool" },
{ TA_ContextMenuUpdate, "context-menu-update" },
{ TA_ContextMenuChoice, "context-menu-choice" },
{ TA_Action, "action" },
{ 0, "" }
};
const FlagString buttons[] = {
{ MB_None, "none" },
{ MB_Left, "left" },
{ MB_Right, "right" },
{ MB_Middle, "middle" },
{ 0, "" }
};
const FlagString modifiers[] = {
std::string ev;
const FlagString categories[] = {
{ TC_Mouse, "mouse" },
{ TC_Keyboard, "keyboard" },
{ TC_Command, "command" },
{ TC_Message, "message" },
{ TC_View, "view" },
{ 0, "" }
};
const FlagString actions[] = {
{ TA_MouseClick, "click" },
{ TA_MouseUp, "button-up" },
{ TA_MouseDown, "button-down" },
{ TA_MouseDrag, "drag" },
{ TA_MouseMotion, "motion" },
{ TA_MouseWheel, "wheel" },
{ TA_KeyUp, "key-up" },
{ TA_KeyDown, "key-down" },
{ TA_ViewRefresh, "view-refresh" },
{ TA_ViewZoom, "view-zoom" },
{ TA_ViewPan, "view-pan" },
{ TA_ViewDirty, "view-dirty" },
{ TA_ChangeLayer, "change-layer" },
{ TA_CancelTool, "cancel-tool" },
{ TA_ContextMenuUpdate, "context-menu-update" },
{ TA_ContextMenuChoice, "context-menu-choice" },
{ TA_Action, "action" },
{ 0, "" }
};
const FlagString buttons[] = {
{ MB_None, "none" },
{ MB_Left, "left" },
{ MB_Right, "right" },
{ MB_Middle, "middle" },
{ 0, "" }
};
const FlagString modifiers[] = {
{ MD_ModShift, "shift" },
{ MD_ModCtrl, "ctrl" },
{ MD_ModAlt, "alt" },
{ 0, "" }
};
ev = "category: ";
ev += flag2string( m_category, categories );
ev += " action: ";
ev += flag2string( m_actions, actions );
if( m_actions & TA_Mouse )
{
ev += " btns: ";
ev += flag2string( m_mouseButtons, buttons );
}
if( m_actions & TA_Keyboard )
{
};
ev = "category: ";
ev += flag2string( m_category, categories );
ev += " action: ";
ev += flag2string( m_actions, actions );
if( m_actions & TA_Mouse )
{
ev += " btns: ";
ev += flag2string( m_mouseButtons, buttons );
}
if( m_actions & TA_Keyboard )
{
char tmp[128];
sprintf( tmp, "key: %d", m_keyCode );
ev += tmp;
}
if( m_actions & ( TA_Mouse | TA_Keyboard ) )
{
ev += " mods: ";
ev += flag2string( m_modifiers, modifiers );
}
if( m_commandId )
{
char tmp[128];
sprintf( tmp, "cmd-id: %d", *m_commandId );
ev += tmp;
}
if( m_commandStr )
ev += "cmd-str: " + ( *m_commandStr );
return ev;
}
if( m_actions & ( TA_Mouse | TA_Keyboard ) )
{
ev += " mods: ";
ev += flag2string( m_modifiers, modifiers );
}
if( m_commandId )
{
char tmp[128];
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
{
string s;
string s;
BOOST_FOREACH( TOOL_EVENT e, m_events )
s += e.Format() + " ";
BOOST_FOREACH( TOOL_EVENT e, m_events )
s += e.Format() + " ";
return s;
return s;
}
......@@ -30,13 +30,13 @@
#include <tool/context_menu.h>
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_BASE( TOOL_Interactive, TOOL_MANAGER::MakeToolId( aName ), aName )
{};
TOOL_BASE( TOOL_Interactive, TOOL_MANAGER::MakeToolId( aName ), aName )
{};
TOOL_INTERACTIVE::~TOOL_INTERACTIVE()
......@@ -46,18 +46,18 @@ TOOL_INTERACTIVE::~TOOL_INTERACTIVE()
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 )
{
m_toolMgr->ScheduleNextState( this, aState, aConditions );
m_toolMgr->ScheduleNextState( this, aState, aConditions );
}
void TOOL_INTERACTIVE::SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger )
{
aMenu->setTool( this );
m_toolMgr->ScheduleContextMenu( this, aMenu, aTrigger );
aMenu->setTool( this );
m_toolMgr->ScheduleContextMenu( this, aMenu, aTrigger );
}
......@@ -52,50 +52,50 @@ using namespace std;
struct TOOL_MANAGER::TOOL_STATE
{
/// The tool itself
TOOL_BASE* theTool;
/// Is the tool active (pending execution) or disabled at the moment
bool idle;
TOOL_BASE* theTool;
/// Flag defining if the tool is waiting for any event (i.e. if it
/// issued a Wait() call).
bool pendingWait;
/// Is the tool active (pending execution) or disabled at the moment
bool idle;
/// Is there a context menu being displayed
bool pendingContextMenu;
/// Flag defining if the tool is waiting for any event (i.e. if it
/// issued a Wait() call).
bool pendingWait;
/// Context menu currently used by the tool
CONTEXT_MENU* contextMenu;
/// Is there a context menu being displayed
bool pendingContextMenu;
/// Defines when the context menu is opened
CONTEXT_MENU_TRIGGER contextMenuTrigger;
/// Context menu currently used by the tool
CONTEXT_MENU* contextMenu;
/// Tool execution context
COROUTINE<int, TOOL_EVENT&>* cofunc;
/// The event that triggered the execution/wakeup of the tool after Wait() call
TOOL_EVENT wakeupEvent;
/// Defines when the context menu is opened
CONTEXT_MENU_TRIGGER contextMenuTrigger;
/// List of events the tool is currently waiting for
TOOL_EVENT_LIST waitEvents;
/// Tool execution context
COROUTINE<int, TOOL_EVENT&>* cofunc;
/// List of possible transitions (ie. association of events and state handlers that are executed
/// upon the event reception
std::vector<TRANSITION> transitions;
/// The event that triggered the execution/wakeup of the tool after Wait() call
TOOL_EVENT wakeupEvent;
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_actionMgr = new ACTION_MANAGER( this );
......@@ -119,37 +119,37 @@ TOOL_MANAGER::~TOOL_MANAGER()
void TOOL_MANAGER::RegisterTool( TOOL_BASE* aTool )
{
TOOL_STATE* st = new TOOL_STATE;
st->theTool = aTool;
st->idle = true;
st->pendingWait = false;
st->pendingContextMenu = false;
st->cofunc = NULL;
st->contextMenuTrigger = CMENU_OFF;
m_toolState[aTool] = st;
m_toolNameIndex[aTool->GetName()] = 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
m_toolState.erase( aTool );
m_toolNameIndex.erase( aTool->GetName() );
m_toolIdIndex.erase( aTool->GetId() );
delete st;
delete aTool;
}
}
TOOL_STATE* st = new TOOL_STATE;
st->theTool = aTool;
st->idle = true;
st->pendingWait = false;
st->pendingContextMenu = false;
st->cofunc = NULL;
st->contextMenuTrigger = CMENU_OFF;
m_toolState[aTool] = st;
m_toolNameIndex[aTool->GetName()] = 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
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,
const TOOL_EVENT_LIST& aConditions )
{
TOOL_STATE* st = m_toolState[aTool];
st->transitions.push_back( TRANSITION( aConditions, aHandler ) );
TOOL_STATE* st = m_toolState[aTool];
st->transitions.push_back( TRANSITION( aConditions, aHandler ) );
}
optional<TOOL_EVENT> TOOL_MANAGER::ScheduleWait( TOOL_BASE* aTool,
const TOOL_EVENT_LIST& aConditions )
{
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;
TOOL_STATE* st = m_toolState[aTool];
// switch context back to event dispatcher loop
st->cofunc->Yield();
// 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;
return st->wakeupEvent;
// switch context back to event dispatcher loop
st->cofunc->Yield();
return st->wakeupEvent;
}
void TOOL_MANAGER::dispatchInternal( TOOL_EVENT& aEvent )
{
// iterate over all registered tools
// iterate over all registered tools
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{
TOOL_STATE* st = m_toolIdIndex[toolId];
// the tool state handler is waiting for events (i.e. called Wait() method)
if( st->pendingWait )
{
if( st->waitEvents.Matches( aEvent ) )
{
// By default, already processed events are not passed further
m_passEvent = false;
// got matching event? clear wait list and wake up the coroutine
st->wakeupEvent = aEvent;
st->pendingWait = false;
st->waitEvents.clear();
if( st->cofunc && !st->cofunc->Resume() )
finishTool( st ); // The couroutine has finished
// If the tool did not request to propagate
// the event to other tools, we should stop it now
if( !m_passEvent )
break;
}
}
// the tool state handler is waiting for events (i.e. called Wait() method)
if( st->pendingWait )
{
if( st->waitEvents.Matches( aEvent ) )
{
// By default, already processed events are not passed further
m_passEvent = false;
// got matching event? clear wait list and wake up the coroutine
st->wakeupEvent = aEvent;
st->pendingWait = false;
st->waitEvents.clear();
if( st->cofunc && !st->cofunc->Resume() )
finishTool( st ); // The couroutine has finished
// If the tool did not request to propagate
// the event to other tools, we should stop it now
if( !m_passEvent )
break;
}
}
}
BOOST_FOREACH( TOOL_STATE* st, m_toolState | boost::adaptors::map_values )
{
// the tool scheduled next state(s) by calling Go()
if( !st->pendingWait )
{
// no state handler in progress - check if there are any transitions (defined by
// Go() method that match the event.
if( st->transitions.size() )
{
BOOST_FOREACH( TRANSITION tr, st->transitions )
{
if( tr.first.Matches( aEvent ) )
{
st->transitions.clear();
// no tool context allocated yet? Create one.
if( !st->cofunc )
st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second );
else
st->cofunc->SetEntry( tr.second );
// got match? Run the handler.
st->cofunc->Call( aEvent );
if( !st->cofunc->Running() )
finishTool( st ); // The couroutine has finished immediately?
}
}
}
}
}
if( !st->pendingWait )
{
// no state handler in progress - check if there are any transitions (defined by
// Go() method that match the event.
if( st->transitions.size() )
{
BOOST_FOREACH( TRANSITION tr, st->transitions )
{
if( tr.first.Matches( aEvent ) )
{
st->transitions.clear();
// no tool context allocated yet? Create one.
if( !st->cofunc )
st->cofunc = new COROUTINE<int, TOOL_EVENT&>( tr.second );
else
st->cofunc->SetEntry( tr.second );
// got match? Run the handler.
st->cofunc->Call( aEvent );
if( !st->cofunc->Running() )
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 )
{
// wxLogDebug( "event: %s", aEvent.Format().c_str() );
// wxLogDebug( "event: %s", aEvent.Format().c_str() );
// Early dispatch of events destined for the TOOL_MANAGER
if( !dispatchStandardEvents( aEvent ) )
return false;
dispatchInternal( aEvent );
dispatchInternal( aEvent );
// popup menu handling
// popup menu handling
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{
TOOL_STATE* st = m_toolIdIndex[toolId];
// 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.
if( st->contextMenuTrigger != CMENU_OFF )
{
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( MB_Right ) )
break;
if( st->contextMenuTrigger != CMENU_OFF )
{
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( MB_Right ) )
break;
st->pendingWait = true;
st->waitEvents = TOOL_EVENT( TC_Any, TA_Any );
st->pendingWait = true;
st->waitEvents = TOOL_EVENT( TC_Any, TA_Any );
if( st->contextMenuTrigger == CMENU_NOW )
st->contextMenuTrigger = CMENU_OFF;
if( st->contextMenuTrigger == CMENU_NOW )
st->contextMenuTrigger = CMENU_OFF;
boost::scoped_ptr<CONTEXT_MENU> menu( new CONTEXT_MENU( *st->contextMenu ) );
GetEditFrame()->PopupMenu( menu->GetMenu() );
//
TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
dispatchInternal( evt );
TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
dispatchInternal( evt );
break;
}
}
break;
}
}
if( m_view->IsDirty() )
{
PCB_EDIT_FRAME* f = static_cast<PCB_EDIT_FRAME*>( GetEditFrame() );
f->GetGalCanvas()->Refresh(); // fixme: ugly hack, provide a method in TOOL_DISPATCHER.
}
if( m_view->IsDirty() )
{
PCB_EDIT_FRAME* f = static_cast<PCB_EDIT_FRAME*>( GetEditFrame() );
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,
CONTEXT_MENU_TRIGGER aTrigger )
{
TOOL_STATE* st = m_toolState[aTool];
st->contextMenu = aMenu;
st->contextMenuTrigger = aTrigger;
// the tool wants the menu immediately? Preempt it and do so :)
if( aTrigger == CMENU_NOW )
st->cofunc->Yield();
TOOL_STATE* st = m_toolState[aTool];
st->contextMenu = aMenu;
st->contextMenuTrigger = aTrigger;
// the tool wants the menu immediately? Preempt it and do so :)
if( aTrigger == CMENU_NOW )
st->cofunc->Yield();
}
TOOL_ID TOOL_MANAGER::MakeToolId( const std::string& aToolName )
{
static int currentId;
return currentId++;
static int currentId;
return currentId++;
}
void TOOL_MANAGER::SetEnvironment( EDA_ITEM* aModel, KiGfx::VIEW* aView,
KiGfx::VIEW_CONTROLS* aViewControls, wxWindow* aFrame )
{
m_model = aModel;
m_view = aView;
m_viewControls = aViewControls;
m_editFrame = aFrame;
// Reset state of the registered tools
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{
TOOL_BASE* tool = m_toolIdIndex[toolId]->theTool;
if( tool->GetType() == TOOL_Interactive )
static_cast<TOOL_INTERACTIVE*>( tool )->Reset();
}
m_model = aModel;
m_view = aView;
m_viewControls = aViewControls;
m_editFrame = aFrame;
// Reset state of the registered tools
BOOST_FOREACH( TOOL_ID toolId, m_activeTools )
{
TOOL_BASE* tool = m_toolIdIndex[toolId]->theTool;
if( tool->GetType() == TOOL_Interactive )
static_cast<TOOL_INTERACTIVE*>( tool )->Reset();
}
}
......
......@@ -87,7 +87,7 @@ public:
{
return m_view;
}
/**
* Function GetViewControls()
* Returns a pointer to the VIEW_CONTROLS instance used in the panel.
......
......@@ -131,7 +131,7 @@ public:
* Saturates the color to a given factor (in HSV model)
*/
COLOR4D& Saturate( double aFactor );
/**
* Function Brightened
* Returns a color that is brighter by a given factor, without modifying object.
......
......@@ -172,11 +172,11 @@ private:
void programInfo( GLuint aProgram );
/**
* @brief Get the shader information.
*
* @param aShader is the shader number.
*/
void shaderInfo( GLuint aShader );
* @brief Get the shader information.
*
* @param aShader is the shader number.
*/
void shaderInfo( GLuint aShader );
/**
* @brief Read the shader source file
......
......@@ -36,278 +36,278 @@ typedef boost::optional<VECTOR2I> OPT_VECTOR2I;
class SEG
{
private:
typedef VECTOR2I::extended_type ecoord;
public:
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
* to an object the segment belongs to (e.g. a line chain) or references to locally stored points
* (m_a, m_b).
*/
VECTOR2I& a, b;
/** Default constructor
* Creates an empty (0, 0) segment, locally-referenced
*/
SEG() : a( m_a ), b( m_b )
{
a = m_a;
b = m_b;
m_is_local = true;
m_index = -1;
}
/**
* Constructor
* 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 )
{
m_a = VECTOR2I( aX1, aY1 );
m_b = VECTOR2I( aX2, aY2 );
a = m_a;
b = m_b;
m_is_local = true;
m_index = -1;
}
/**
* Constructor
* 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 )
{
a = m_a;
b = m_b;
m_is_local = true;
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
*/
SEG ( const SEG& aSeg ) : a( m_a ), b( m_b )
{
if (aSeg.m_is_local)
{
m_a = aSeg.m_a;
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 )
{
a = aSeg.a;
b = aSeg.b;
m_a = aSeg.m_a;
m_b = aSeg.m_b;
m_index = aSeg.m_index;
m_is_local = aSeg.m_is_local;
return *this;
}
/**
* Function LineProject()
*
* Computes the perpendicular projection point of aP on a line passing through
* ends of the segment.
* @param aP point to project
* @return projected point
*/
VECTOR2I LineProject( const VECTOR2I& aP ) const;
/**
* 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()
*
* Computes a point on the segment (this) that is closest to point aP.
* @return: nearest point
*/
const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
/**
* Function Intersect()
*
* Computes intersection point of segment (this) with segment aSeg.
* @param aSeg: segment to intersect with
* @param aIgnoreEndpoints: don't treat corner cases (i.e. end of one segment touching the other)
* as intersections.
* @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()
*
* 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
{
return sqrt( SquaredDistance( aP ) );
}
/**
* 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 );
}
/**
* Function Length()
*
* Returns the length (this)
* @return length
*/
int Length() const
{
return ( a - b ).EuclideanNorm();
}
ecoord SquaredLength() const
{
return ( a - b ).SquaredEuclideanNorm();
}
/**
* 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;
private:
typedef VECTOR2I::extended_type ecoord;
public:
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
* to an object the segment belongs to (e.g. a line chain) or references to locally stored points
* (m_a, m_b).
*/
VECTOR2I& a, b;
/** Default constructor
* Creates an empty (0, 0) segment, locally-referenced
*/
SEG() : a( m_a ), b( m_b )
{
a = m_a;
b = m_b;
m_is_local = true;
m_index = -1;
}
/**
* Constructor
* 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 )
{
m_a = VECTOR2I( aX1, aY1 );
m_b = VECTOR2I( aX2, aY2 );
a = m_a;
b = m_b;
m_is_local = true;
m_index = -1;
}
/**
* Constructor
* 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 )
{
a = m_a;
b = m_b;
m_is_local = true;
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
*/
SEG ( const SEG& aSeg ) : a( m_a ), b( m_b )
{
if (aSeg.m_is_local)
{
m_a = aSeg.m_a;
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 )
{
a = aSeg.a;
b = aSeg.b;
m_a = aSeg.m_a;
m_b = aSeg.m_b;
m_index = aSeg.m_index;
m_is_local = aSeg.m_is_local;
return *this;
}
/**
* Function LineProject()
*
* Computes the perpendicular projection point of aP on a line passing through
* ends of the segment.
* @param aP point to project
* @return projected point
*/
VECTOR2I LineProject( const VECTOR2I& aP ) const;
/**
* 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()
*
* Computes a point on the segment (this) that is closest to point aP.
* @return: nearest point
*/
const VECTOR2I NearestPoint( const VECTOR2I &aP ) const;
/**
* Function Intersect()
*
* Computes intersection point of segment (this) with segment aSeg.
* @param aSeg: segment to intersect with
* @param aIgnoreEndpoints: don't treat corner cases (i.e. end of one segment touching the other)
* as intersections.
* @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()
*
* 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
{
return sqrt( SquaredDistance( aP ) );
}
/**
* 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 );
}
/**
* Function Length()
*
* Returns the length (this)
* @return length
*/
int Length() const
{
return ( a - b ).EuclideanNorm();
}
ecoord SquaredLength() const
{
return ( a - b ).SquaredEuclideanNorm();
}
/**
* 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
{
// fixme: numerical errors for large integers
assert( false );
return VECTOR2I( 0, 0 );
// fixme: numerical errors for large integers
assert( false );
return VECTOR2I( 0, 0 );
}
inline int SEG::LineDistance( const VECTOR2I& aP, bool aDetermineSide ) const
{
ecoord p = a.y - b.y;
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 );
......@@ -321,14 +321,14 @@ inline const VECTOR2I SEG::NearestPoint( const VECTOR2I& aP ) const
if( l_squared == 0 )
return a;
ecoord t = d.Dot( aP - a );
if( t < 0 )
return a;
else if( t > l_squared )
return b;
int xp = rescale( t, (ecoord)d.x, 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 )
{
if( aSeg.m_is_local )
aStream << "[ local " << aSeg.a << " - " << aSeg.b << " ]";
aStream << "[ local " << aSeg.a << " - " << aSeg.b << " ]";
return aStream;
}
......
......@@ -36,109 +36,109 @@
*/
enum ShapeType {
SH_RECT = 0, ///> axis-aligned rectangle
SH_SEGMENT, ///> line segment
SH_LINE_CHAIN, ///> line chain (polyline)
SH_CIRCLE ///> circle
SH_RECT = 0, ///> axis-aligned rectangle
SH_SEGMENT, ///> line segment
SH_LINE_CHAIN, ///> line chain (polyline)
SH_CIRCLE ///> circle
};
/**
* Class SHAPE
*
*
* Represents an abstract shape on 2D plane.
*/
*/
class SHAPE {
protected:
typedef VECTOR2I::extended_type ecoord;
public:
/**
* Constructor
*
* Creates an empty shape of type aType
*/
SHAPE ( ShapeType aType ) : m_type( aType ) { };
// Destructor
virtual ~SHAPE() {};
/**
* Function Type()
*
* Returns the type of the shape.
* @retval the type
*/
ShapeType Type() const { return m_type; }
/**
* Function Clone()
*
* Returns a dynamically allocated copy of the shape
* @retval copy of the shape
*/
virtual SHAPE* Clone() const {
assert( false );
return NULL;
};
/**
* Function Collide()
*
* Checks if the boundary of shape (this) lies closer to the point aP than aClearance, indicating
* a collision.
* @return true, if there is a collision.
*/
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const
{
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()
*
* 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;
protected:
typedef VECTOR2I::extended_type ecoord;
public:
/**
* Constructor
*
* Creates an empty shape of type aType
*/
SHAPE ( ShapeType aType ) : m_type( aType ) { };
// Destructor
virtual ~SHAPE() {};
/**
* Function Type()
*
* Returns the type of the shape.
* @retval the type
*/
ShapeType Type() const { return m_type; }
/**
* Function Clone()
*
* Returns a dynamically allocated copy of the shape
* @retval copy of the shape
*/
virtual SHAPE* Clone() const {
assert( false );
return NULL;
};
/**
* Function Collide()
*
* Checks if the boundary of shape (this) lies closer to the point aP than aClearance, indicating
* a collision.
* @return true, if there is a collision.
*/
virtual bool Collide( const VECTOR2I& aP, int aClearance = 0 ) const
{
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()
*
* Computes a center-of-mass of the shape
* @return the center-of-mass point
*/
virtual VECTOR2I Centre() const
{
return BBox( 0 ).Centre(); // if nothing better is available....
}
private:
///> type of our shape
ShapeType m_type;
};
......
......@@ -30,48 +30,48 @@
class SHAPE_CIRCLE : public SHAPE {
public:
SHAPE_CIRCLE():
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( SH_CIRCLE ), m_radius( 0 ) {};
~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
{
const VECTOR2I rc( m_radius + aClearance, m_radius + aClearance );
return BOX2I( m_center - rc, rc * 2 );
}
~SHAPE_CIRCLE() {};
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
{
int rc = aClearance + m_radius;
return aSeg.Distance( m_center ) <= rc;
}
const BOX2I BBox( int aClearance = 0 ) const
{
const VECTOR2I rc( m_radius + aClearance, m_radius + aClearance );
return BOX2I( m_center - rc, rc * 2 );
}
void SetRadius( int aRadius )
{
m_radius = aRadius;
}
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
{
int rc = aClearance + m_radius;
return aSeg.Distance( m_center ) <= rc;
}
void SetCenter( const VECTOR2I& aCenter )
{
m_center = aCenter;
}
void SetRadius( int aRadius )
{
m_radius = aRadius;
}
int GetRadius() const
{
return m_radius;
}
void SetCenter( const VECTOR2I& aCenter )
{
m_center = aCenter;
}
const VECTOR2I GetCenter() const
{
return m_center;
}
int GetRadius() const
{
return m_radius;
}
const VECTOR2I GetCenter() const
{
return m_center;
}
private:
int m_radius;
VECTOR2I m_center;
int m_radius;
VECTOR2I m_center;
};
#endif
......@@ -276,11 +276,11 @@ class SHAPE_INDEX
{
BOX2I box = aShape->BBox();
box.Inflate( aMinDistance );
int min[2] = { box.GetX(), box.GetY() };
int max[2] = { box.GetRight(), box.GetBottom() };
return this->m_tree->Search( min, max, aVisitor );
int min[2] = { box.GetX(), box.GetY() };
int max[2] = { box.GetRight(), box.GetBottom() };
return this->m_tree->Search( min, max, aVisitor );
}
/**
......
......@@ -29,205 +29,205 @@
template <class T> const SHAPE* defaultShapeFunctor( const T aItem )
{
return aItem->GetShape();
return aItem->GetShape();
}
template <class T, const SHAPE* (ShapeFunctor)(const T) = defaultShapeFunctor<T> >
class SHAPE_INDEX_LIST {
struct ShapeEntry {
ShapeEntry( T aParent )
{
shape = ShapeFunctor( aParent );
bbox = shape->BBox( 0 );
parent = aParent;
}
~ShapeEntry()
{
}
T parent;
const SHAPE* shape;
BOX2I bbox;
};
typedef std::vector<ShapeEntry> ShapeVec;
typedef typename std::vector<ShapeEntry>::iterator ShapeVecIter;
struct ShapeEntry {
ShapeEntry( T aParent )
{
shape = ShapeFunctor( aParent );
bbox = shape->BBox( 0 );
parent = aParent;
}
~ShapeEntry()
{
}
T parent;
const SHAPE* shape;
BOX2I bbox;
};
typedef std::vector<ShapeEntry> ShapeVec;
typedef typename std::vector<ShapeEntry>::iterator ShapeVecIter;
public:
// "Normal" iterator interface, for STL algorithms.
class iterator {
public:
iterator() {};
iterator( ShapeVecIter aCurrent )
: m_current( aCurrent ) {};
iterator( const iterator &aB ) :
m_current( aB.m_current ) {};
T operator*() const
{
return (*m_current).parent;
}
void operator++()
{
++m_current;
}
iterator& operator++( int aDummy )
{
++m_current;
return *this;
}
bool operator==( const iterator& aRhs ) const
{
return m_current == aRhs.m_current;
}
bool operator!=( const iterator& aRhs ) const
{
return m_current != aRhs.m_current;
}
const iterator& operator=( const iterator& aRhs )
{
m_current = aRhs.m_current;
return *this;
}
private:
ShapeVecIter m_current;
};
// "Query" iterator, for iterating over a set of spatially matching shapes.
class query_iterator {
public:
query_iterator()
{
}
query_iterator( ShapeVecIter aCurrent, ShapeVecIter aEnd, SHAPE* aShape,
int aMinDistance, bool aExact ) :
m_end( aEnd ),
m_current( aCurrent ),
m_shape( aShape ),
m_minDistance( aMinDistance ),
m_exact( aExact )
{
if( aShape )
{
m_refBBox = aShape->BBox();
next();
}
}
query_iterator( const query_iterator &aB ) :
m_end( aB.m_end ),
m_current( aB.m_current ),
m_shape( aB.m_shape ),
m_minDistance( aB.m_minDistance ),
m_exact( aB.m_exact ),
m_refBBox( aB.m_refBBox )
{
}
T operator*() const
{
return (*m_current).parent;
}
query_iterator& operator++()
{
++m_current;
next();
return *this;
}
query_iterator& operator++( int aDummy )
{
++m_current;
next();
return *this;
}
bool operator==( const query_iterator& aRhs ) const
{
return m_current == aRhs.m_current;
}
bool operator!=( const query_iterator& aRhs ) const
{
return m_current != aRhs.m_current;
}
const query_iterator& operator=( const query_iterator& aRhs )
{
m_end = aRhs.m_end;
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:
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;
}
++m_current;
}
}
ShapeVecIter m_end;
ShapeVecIter m_current;
BOX2I m_refBBox;
bool m_exact;
SHAPE *m_shape;
int m_minDistance;
};
void Add( T aItem )
{
ShapeEntry s( aItem );
m_shapes.push_back(s);
}
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() )
return;
m_shapes.erase( i );
}
int Size() const
{
return m_shapes.size();
}
template<class Visitor>
// "Normal" iterator interface, for STL algorithms.
class iterator {
public:
iterator() {};
iterator( ShapeVecIter aCurrent )
: m_current( aCurrent ) {};
iterator( const iterator &aB ) :
m_current( aB.m_current ) {};
T operator*() const
{
return (*m_current).parent;
}
void operator++()
{
++m_current;
}
iterator& operator++( int aDummy )
{
++m_current;
return *this;
}
bool operator==( const iterator& aRhs ) const
{
return m_current == aRhs.m_current;
}
bool operator!=( const iterator& aRhs ) const
{
return m_current != aRhs.m_current;
}
const iterator& operator=( const iterator& aRhs )
{
m_current = aRhs.m_current;
return *this;
}
private:
ShapeVecIter m_current;
};
// "Query" iterator, for iterating over a set of spatially matching shapes.
class query_iterator {
public:
query_iterator()
{
}
query_iterator( ShapeVecIter aCurrent, ShapeVecIter aEnd, SHAPE* aShape,
int aMinDistance, bool aExact ) :
m_end( aEnd ),
m_current( aCurrent ),
m_shape( aShape ),
m_minDistance( aMinDistance ),
m_exact( aExact )
{
if( aShape )
{
m_refBBox = aShape->BBox();
next();
}
}
query_iterator( const query_iterator &aB ) :
m_end( aB.m_end ),
m_current( aB.m_current ),
m_shape( aB.m_shape ),
m_minDistance( aB.m_minDistance ),
m_exact( aB.m_exact ),
m_refBBox( aB.m_refBBox )
{
}
T operator*() const
{
return (*m_current).parent;
}
query_iterator& operator++()
{
++m_current;
next();
return *this;
}
query_iterator& operator++( int aDummy )
{
++m_current;
next();
return *this;
}
bool operator==( const query_iterator& aRhs ) const
{
return m_current == aRhs.m_current;
}
bool operator!=( const query_iterator& aRhs ) const
{
return m_current != aRhs.m_current;
}
const query_iterator& operator=( const query_iterator& aRhs )
{
m_end = aRhs.m_end;
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:
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;
}
++m_current;
}
}
ShapeVecIter m_end;
ShapeVecIter m_current;
BOX2I m_refBBox;
bool m_exact;
SHAPE *m_shape;
int m_minDistance;
};
void Add( T aItem )
{
ShapeEntry s( aItem );
m_shapes.push_back(s);
}
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() )
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
{
ShapeVecIter i;
......@@ -251,33 +251,33 @@ public:
return n;
}
void 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()
{
return query_iterator( m_shapes.end(), m_shapes.end(), NULL, 0, false );
}
iterator begin()
{
return iterator( m_shapes.begin() );
}
iterator end()
{
return iterator( m_shapes.end() );
}
void 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()
{
return query_iterator( m_shapes.end(), m_shapes.end(), NULL, 0, false );
}
iterator begin()
{
return iterator( m_shapes.begin() );
}
iterator end()
{
return iterator( m_shapes.end() );
}
private:
ShapeVec m_shapes;
ShapeVec m_shapes;
};
#endif
......@@ -38,504 +38,504 @@
* Class SHAPE_LINE_CHAIN
*
* 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!
*/
class SHAPE_LINE_CHAIN : public SHAPE {
private:
typedef std::vector<VECTOR2I>::iterator point_iter;
typedef std::vector<VECTOR2I>::const_iterator point_citer;
public:
/**
* Struct Intersection
*
* Represents an intersection between two line segments
*/
struct Intersection
{
/// segment belonging from the (this) argument of Intersect()
SEG our;
/// segment belonging from the aOther argument of Intersect()
SEG their;
/// point of intersection between our and their.
VECTOR2I p;
};
typedef std::vector<Intersection> Intersections;
/**
* Constructor
* Initializes an empty line chain.
*/
SHAPE_LINE_CHAIN():
SHAPE( SH_LINE_CHAIN ), m_closed( false ) {};
/**
* Copy Constructor
*/
SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape ) :
SHAPE( SH_LINE_CHAIN ), m_points( aShape.m_points ), m_closed( aShape.m_closed ) {};
/**
* Constructor
* Initializes a 2-point line chain (a single segment)
*/
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB ) :
SHAPE( SH_LINE_CHAIN ),
m_closed( false )
{
m_points.resize( 2 );
m_points[0] = aA;
m_points[1] = aB;
}
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ):
SHAPE( SH_LINE_CHAIN ),
m_closed( false )
{
m_points.resize( 3 );
m_points[0] = aA;
m_points[1] = aB;
m_points[2] = aC;
}
SHAPE_LINE_CHAIN(const VECTOR2I* aV, int aCount ) :
SHAPE( SH_LINE_CHAIN ),
m_closed( false )
{
m_points.resize( aCount );
for( int i = 0; i < aCount; i++ )
m_points[i] = *aV++;
}
~SHAPE_LINE_CHAIN() {};
/**
* Function Clear()
* Removes all points from the line chain.
*/
void Clear()
{
m_points.clear();
m_closed = false;
}
/**
* Function SetClosed()
*
* 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.
*/
void SetClosed( bool aClosed )
{
m_closed = aClosed;
}
/**
* Function IsClosed()
*
* @return aClosed: true, when our line is closed.
*/
bool IsClosed() const
{
return m_closed;
}
/**
* Function SegmentCount()
*
* Returns number of segments in this line chain.
* @return number of segments
*/
int SegmentCount() const
{
int c = m_points.size() - 1;
if( m_closed )
c++;
return std::max( 0, c );
}
/**
* Function PointCount()
*
* Returns the number of points (vertices) in this line chain
* @return number of points
*/
int PointCount() const
{
return m_points.size();
}
/**
* Function Segment()
*
* 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.
* @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)
* @return SEG referenced to given segment in the line chain
*/
SEG Segment( int aIndex )
{
if( aIndex < 0 )
aIndex += SegmentCount();
if( aIndex == ( m_points.size() - 1 ) && m_closed )
return SEG( m_points[aIndex], m_points[0], aIndex );
else
return SEG( m_points[aIndex], m_points[aIndex + 1], aIndex );
}
/**
* Function CSegment()
*
* 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
* the last segment in the line chain)
* @return SEG referenced to given segment in the line chain
*/
const SEG CSegment( int aIndex ) const
{
if( aIndex < 0 )
aIndex += SegmentCount();
if( aIndex == ( m_points.size() - 1 ) && m_closed )
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
const_cast<VECTOR2I&>( m_points[0] ), aIndex );
else
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
const_cast<VECTOR2I&>( m_points[aIndex + 1] ), aIndex );
}
/**
* Function Point()
*
* Returns a reference to a given point in the line chain.
* @param aIndex index of the point
* @return reference to the point
*/
VECTOR2I& Point( int aIndex )
{
if( aIndex < 0 )
aIndex += PointCount();
return m_points[aIndex];
}
/**
* Function CPoint()
*
* Returns a const reference to a given point in the line chain.
* @param aIndex index of the point
* @return const reference to the point
*/
const VECTOR2I& CPoint( int aIndex ) const
{
if( aIndex < 0 )
aIndex += PointCount();
return m_points[aIndex];
}
/// @copydoc SHAPE::BBox()
const BOX2I BBox( int aClearance = 0 ) const
{
BOX2I bbox;
bbox.Compute( m_points );
return bbox;
}
/**
* Function Collide()
*
* Checks if point aP lies closer to us than aClearance.
* @param aP the point 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 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()
*
* Reverses point order in the line chain.
* @return line chain with reversed point order (original A-B-C-D: returned D-C-B-A)
*/
const SHAPE_LINE_CHAIN Reverse() const;
/**
* Function Length()
*
* Returns length of the line chain in Euclidean metric.
* @return length of the line chain
*/
int Length() 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()
*
* Appends a new point at the end of the line chain.
* @param aP the new point
*/
void Append( const VECTOR2I& aP )
{
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()
*
* Appends another line chain at the end.
* @param aOtherLine the line chain to be appended.
*/
void Append( const SHAPE_LINE_CHAIN& aOtherLine )
{
if( aOtherLine.PointCount() == 0 )
return;
else if( PointCount() == 0 || aOtherLine.CPoint( 0 ) != CPoint( -1 ) )
{
const VECTOR2I p = aOtherLine.CPoint( 0 );
m_points.push_back( p );
m_bbox.Merge( p );
}
for( int i = 1; i < aOtherLine.PointCount(); i++ )
{
const VECTOR2I p = aOtherLine.CPoint( i );
m_points.push_back( p );
m_bbox.Merge( p );
}
}
/**
* 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 Replace()
*
* Replaces points with indices in range [start_index, end_index] with the points from
* 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()
*
* 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 );
/**
* 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
{
compareOriginDistance( VECTOR2I& aOrigin ):
m_origin( aOrigin ) {};
bool operator()( const Intersection& aA, const Intersection& aB )
{
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;
private:
typedef std::vector<VECTOR2I>::iterator point_iter;
typedef std::vector<VECTOR2I>::const_iterator point_citer;
public:
/**
* Struct Intersection
*
* Represents an intersection between two line segments
*/
struct Intersection
{
/// segment belonging from the (this) argument of Intersect()
SEG our;
/// segment belonging from the aOther argument of Intersect()
SEG their;
/// point of intersection between our and their.
VECTOR2I p;
};
typedef std::vector<Intersection> Intersections;
/**
* Constructor
* Initializes an empty line chain.
*/
SHAPE_LINE_CHAIN():
SHAPE( SH_LINE_CHAIN ), m_closed( false ) {};
/**
* Copy Constructor
*/
SHAPE_LINE_CHAIN( const SHAPE_LINE_CHAIN& aShape ) :
SHAPE( SH_LINE_CHAIN ), m_points( aShape.m_points ), m_closed( aShape.m_closed ) {};
/**
* Constructor
* Initializes a 2-point line chain (a single segment)
*/
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB ) :
SHAPE( SH_LINE_CHAIN ),
m_closed( false )
{
m_points.resize( 2 );
m_points[0] = aA;
m_points[1] = aB;
}
SHAPE_LINE_CHAIN( const VECTOR2I& aA, const VECTOR2I& aB, const VECTOR2I& aC ):
SHAPE( SH_LINE_CHAIN ),
m_closed( false )
{
m_points.resize( 3 );
m_points[0] = aA;
m_points[1] = aB;
m_points[2] = aC;
}
SHAPE_LINE_CHAIN(const VECTOR2I* aV, int aCount ) :
SHAPE( SH_LINE_CHAIN ),
m_closed( false )
{
m_points.resize( aCount );
for( int i = 0; i < aCount; i++ )
m_points[i] = *aV++;
}
~SHAPE_LINE_CHAIN() {};
/**
* Function Clear()
* Removes all points from the line chain.
*/
void Clear()
{
m_points.clear();
m_closed = false;
}
/**
* Function SetClosed()
*
* 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.
*/
void SetClosed( bool aClosed )
{
m_closed = aClosed;
}
/**
* Function IsClosed()
*
* @return aClosed: true, when our line is closed.
*/
bool IsClosed() const
{
return m_closed;
}
/**
* Function SegmentCount()
*
* Returns number of segments in this line chain.
* @return number of segments
*/
int SegmentCount() const
{
int c = m_points.size() - 1;
if( m_closed )
c++;
return std::max( 0, c );
}
/**
* Function PointCount()
*
* Returns the number of points (vertices) in this line chain
* @return number of points
*/
int PointCount() const
{
return m_points.size();
}
/**
* Function Segment()
*
* 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.
* @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)
* @return SEG referenced to given segment in the line chain
*/
SEG Segment( int aIndex )
{
if( aIndex < 0 )
aIndex += SegmentCount();
if( aIndex == ( m_points.size() - 1 ) && m_closed )
return SEG( m_points[aIndex], m_points[0], aIndex );
else
return SEG( m_points[aIndex], m_points[aIndex + 1], aIndex );
}
/**
* Function CSegment()
*
* 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
* the last segment in the line chain)
* @return SEG referenced to given segment in the line chain
*/
const SEG CSegment( int aIndex ) const
{
if( aIndex < 0 )
aIndex += SegmentCount();
if( aIndex == ( m_points.size() - 1 ) && m_closed )
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
const_cast<VECTOR2I&>( m_points[0] ), aIndex );
else
return SEG( const_cast<VECTOR2I&>( m_points[aIndex] ),
const_cast<VECTOR2I&>( m_points[aIndex + 1] ), aIndex );
}
/**
* Function Point()
*
* Returns a reference to a given point in the line chain.
* @param aIndex index of the point
* @return reference to the point
*/
VECTOR2I& Point( int aIndex )
{
if( aIndex < 0 )
aIndex += PointCount();
return m_points[aIndex];
}
/**
* Function CPoint()
*
* Returns a const reference to a given point in the line chain.
* @param aIndex index of the point
* @return const reference to the point
*/
const VECTOR2I& CPoint( int aIndex ) const
{
if( aIndex < 0 )
aIndex += PointCount();
return m_points[aIndex];
}
/// @copydoc SHAPE::BBox()
const BOX2I BBox( int aClearance = 0 ) const
{
BOX2I bbox;
bbox.Compute( m_points );
return bbox;
}
/**
* Function Collide()
*
* Checks if point aP lies closer to us than aClearance.
* @param aP the point 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 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()
*
* Reverses point order in the line chain.
* @return line chain with reversed point order (original A-B-C-D: returned D-C-B-A)
*/
const SHAPE_LINE_CHAIN Reverse() const;
/**
* Function Length()
*
* Returns length of the line chain in Euclidean metric.
* @return length of the line chain
*/
int Length() 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()
*
* Appends a new point at the end of the line chain.
* @param aP the new point
*/
void Append( const VECTOR2I& aP )
{
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()
*
* Appends another line chain at the end.
* @param aOtherLine the line chain to be appended.
*/
void Append( const SHAPE_LINE_CHAIN& aOtherLine )
{
if( aOtherLine.PointCount() == 0 )
return;
else if( PointCount() == 0 || aOtherLine.CPoint( 0 ) != CPoint( -1 ) )
{
const VECTOR2I p = aOtherLine.CPoint( 0 );
m_points.push_back( p );
m_bbox.Merge( p );
}
for( int i = 1; i < aOtherLine.PointCount(); i++ )
{
const VECTOR2I p = aOtherLine.CPoint( i );
m_points.push_back( p );
m_bbox.Merge( p );
}
}
/**
* 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 Replace()
*
* Replaces points with indices in range [start_index, end_index] with the points from
* 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()
*
* 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 );
/**
* 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
{
compareOriginDistance( VECTOR2I& aOrigin ):
m_origin( aOrigin ) {};
bool operator()( const Intersection& aA, const Intersection& aB )
{
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
......@@ -31,114 +31,114 @@
#include <geometry/seg.h>
class SHAPE_RECT : public SHAPE {
public:
/**
* Constructor
* Creates an empty (0-sized) rectangle
*/
SHAPE_RECT() :
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
* Creates a rectangle defined by top-left corner aP0, width aW and height aH.
*/
SHAPE_RECT( const VECTOR2I &aP0, int aW, int aH ) :
SHAPE( SH_RECT ), m_p0( aP0 ), m_w( aW ), m_h( aH ) {};
/// @copydoc SHAPE::BBox()
const BOX2I BBox(int aClearance = 0) const
{
BOX2I bbox( VECTOR2I( m_p0.x - aClearance, m_p0.y - aClearance ),
VECTOR2I( m_w + 2 * aClearance, m_h + 2 * aClearance ) );
//printf("bb : %s\n",bbox.Format().c_str());
return bbox;
}
/**
* Function Diagonal()
*
* Returns length of the diagonal of the rectangle
* @return diagonal length
*/
int Diagonal() const
{
return VECTOR2I( m_w, m_h ).EuclideanNorm();
}
/// @copydoc SHAPE::Collide()
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
{
//VECTOR2I pmin = VECTOR2I(std::min(aSeg.a.x, aSeg.b.x), std::min(aSeg.a.y, aSeg.b.y));
//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));
//if (BBox(0).SquaredDistance(r) > aClearance * aClearance)
// return false;
if( BBox( 0 ).Contains( aSeg.a ) || BBox( 0 ).Contains( aSeg.b ) )
return true;
VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ),
VECTOR2I( m_p0.x, m_p0.y + m_h ),
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++ )
{
SEG s( vts[i], vts[i + 1], i );
if( s.Distance( aSeg ) <= aClearance )
return true;
}
return false;
};
/**
* Function GetPosition()
*
* @return top-left corner of the rectangle
*/
const VECTOR2I& GetPosition() const { return m_p0; }
/**
* Function GetSize()
*
* @return size of the rectangle
*/
const VECTOR2I GetSize() const { return VECTOR2I( m_w, 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;
};
public:
/**
* Constructor
* Creates an empty (0-sized) rectangle
*/
SHAPE_RECT() :
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
* Creates a rectangle defined by top-left corner aP0, width aW and height aH.
*/
SHAPE_RECT( const VECTOR2I &aP0, int aW, int aH ) :
SHAPE( SH_RECT ), m_p0( aP0 ), m_w( aW ), m_h( aH ) {};
/// @copydoc SHAPE::BBox()
const BOX2I BBox(int aClearance = 0) const
{
BOX2I bbox( VECTOR2I( m_p0.x - aClearance, m_p0.y - aClearance ),
VECTOR2I( m_w + 2 * aClearance, m_h + 2 * aClearance ) );
//printf("bb : %s\n",bbox.Format().c_str());
return bbox;
}
/**
* Function Diagonal()
*
* Returns length of the diagonal of the rectangle
* @return diagonal length
*/
int Diagonal() const
{
return VECTOR2I( m_w, m_h ).EuclideanNorm();
}
/// @copydoc SHAPE::Collide()
bool Collide( const SEG& aSeg, int aClearance = 0 ) const
{
//VECTOR2I pmin = VECTOR2I(std::min(aSeg.a.x, aSeg.b.x), std::min(aSeg.a.y, aSeg.b.y));
//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));
//if (BBox(0).SquaredDistance(r) > aClearance * aClearance)
// return false;
if( BBox( 0 ).Contains( aSeg.a ) || BBox( 0 ).Contains( aSeg.b ) )
return true;
VECTOR2I vts[] = { VECTOR2I( m_p0.x, m_p0.y ),
VECTOR2I( m_p0.x, m_p0.y + m_h ),
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++ )
{
SEG s( vts[i], vts[i + 1], i );
if( s.Distance( aSeg ) <= aClearance )
return true;
}
return false;
};
/**
* Function GetPosition()
*
* @return top-left corner of the rectangle
*/
const VECTOR2I& GetPosition() const { return m_p0; }
/**
* Function GetSize()
*
* @return size of the rectangle
*/
const VECTOR2I GetSize() const { return VECTOR2I( m_w, 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
......@@ -66,7 +66,7 @@ public:
BOX2( const Vec& aPos, const Vec& aSize ) :
m_Pos( aPos ),
m_Size( aSize )
{
{
Normalize();
}
......@@ -420,7 +420,7 @@ public:
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 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
......
......@@ -224,7 +224,7 @@ public:
/// Division with a factor
VECTOR2<T> operator/( const T& aFactor ) const;
/// Equality operator
const bool operator==( const VECTOR2<T>& aVector ) const;
......
......@@ -37,105 +37,105 @@ class TOOL_INTERACTIVE;
* Defines the structure of a context (usually right-click) popup menu
* for a given tool.
*/
class CONTEXT_MENU
class CONTEXT_MENU
{
public:
///> Default constructor
CONTEXT_MENU();
///> Copy constructor
CONTEXT_MENU( const CONTEXT_MENU& aMenu );
/**
* Function SetTitle()
* Sets title for the context menu. The title is shown as a text label shown on the top of
* the menu.
* @param aTitle is the new title.
*/
void SetTitle( const wxString& aTitle );
/**
* Function Add()
* Adds an entry to the menu. After highlighting/selecting the entry, a TOOL_EVENT command is
* sent that contains ID of the entry.
* @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.
*/
void Add( const wxString& aLabel, int aId );
/**
* Function Add()
* 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.
* @param aAction is the action to be added to menu entry.
*/
void Add( const TOOL_ACTION& aAction );
/**
* Function Clear()
* Removes all the entries from the menu (as well as its title). It leaves the menu in the
* initial state.
*/
void Clear();
/**
* Function GetMenu()
* Returns the instance of wxMenu object used to display the menu.
*/
wxMenu* GetMenu() const
{
return const_cast<wxMenu*>( &m_menu );
}
CONTEXT_MENU();
///> Copy constructor
CONTEXT_MENU( const CONTEXT_MENU& aMenu );
/**
* Function SetTitle()
* Sets title for the context menu. The title is shown as a text label shown on the top of
* the menu.
* @param aTitle is the new title.
*/
void SetTitle( const wxString& aTitle );
/**
* Function Add()
* Adds an entry to the menu. After highlighting/selecting the entry, a TOOL_EVENT command is
* sent that contains ID of the entry.
* @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.
*/
void Add( const wxString& aLabel, int aId );
/**
* Function Add()
* 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.
* @param aAction is the action to be added to menu entry.
*/
void Add( const TOOL_ACTION& aAction );
/**
* Function Clear()
* Removes all the entries from the menu (as well as its title). It leaves the menu in the
* initial state.
*/
void Clear();
/**
* Function GetMenu()
* Returns the instance of wxMenu object used to display the menu.
*/
wxMenu* GetMenu() const
{
return const_cast<wxMenu*>( &m_menu );
}
private:
///> Class CMEventHandler takes care of handling menu events. After reception of particular
///> events, it translates them to TOOL_EVENTs that may control tools.
class CMEventHandler : public wxEvtHandler
{
public:
///> Default constructor
///> aMenu is the CONTEXT_MENU instance for which it handles events.
CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {};
///> Handler for menu events.
void onEvent( wxEvent& aEvent );
private:
///> CONTEXT_MENU instance for which it handles events.
CONTEXT_MENU* m_menu;
};
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()
* 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;
///> Flag indicating that the menu title was set up.
bool m_titleSet;
///> Instance of wxMenu used for display of the context menu.
wxMenu m_menu;
///> Instance of menu event handler.
CMEventHandler m_handler;
///> Creator of the menu
TOOL_INTERACTIVE* m_tool;
///> Class CMEventHandler takes care of handling menu events. After reception of particular
///> events, it translates them to TOOL_EVENTs that may control tools.
class CMEventHandler : public wxEvtHandler
{
public:
///> Default constructor
///> aMenu is the CONTEXT_MENU instance for which it handles events.
CMEventHandler( CONTEXT_MENU* aMenu ) : m_menu( aMenu ) {};
///> Handler for menu events.
void onEvent( wxEvent& aEvent );
private:
///> CONTEXT_MENU instance for which it handles events.
CONTEXT_MENU* m_menu;
};
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()
* 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;
///> Flag indicating that the menu title was set up.
bool m_titleSet;
///> Instance of wxMenu used for display of the context menu.
wxMenu m_menu;
///> Instance of menu event handler.
CMEventHandler m_handler;
///> Creator of the menu
TOOL_INTERACTIVE* m_tool;
/// Menu items with ID higher than that are considered TOOL_ACTIONs
static const int m_actionId = 10000;
......
......@@ -34,13 +34,13 @@
/**
Class COROUNTINE.
Implements a coroutine. Wikipedia has a good explanation:
"Coroutines are computer program components that generalize subroutines to
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 computer program components that generalize subroutines to
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
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,
we avoid concurrency problems such as locking / race conditions.
......@@ -56,82 +56,82 @@ template<class ReturnType, class ArgType>
class COROUTINE
{
public:
COROUTINE()
{
m_stackSize = c_defaultStackSize;
m_stack = 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
* Creates a coroutine from a delegate object
*/
COROUTINE( DELEGATE<ReturnType, ArgType> aEntry ) :
COROUTINE()
{
m_stackSize = c_defaultStackSize;
m_stack = 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
* 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 )
{};
{};
~COROUTINE()
{
~COROUTINE()
{
if( m_saved )
delete m_saved;
if( m_stack )
free( m_stack );
}
/**
* Function Yield()
*
* Stops execution of the coroutine and returns control to the caller.
* After a yield, Call() or Resume() methods invoked by the caller will
* immediately return true, indicating that we are not done yet, just asleep.
*/
void Yield()
{
boost::context::jump_fcontext( m_self, m_saved, 0 );
}
/**
* Function Yield()
*
* Yield with a value - passes a value of given type to the caller.
* Useful for implementing generator objects.
*/
void Yield( ReturnType& retVal )
{
m_retVal = retVal;
boost::context::jump_fcontext( m_self, m_saved, 0 );
}
/**
<F11>* Function SetEntry()
*
* Defines the entry point for the coroutine, if not set in the constructor.
*/
void SetEntry( DELEGATE<ReturnType, ArgType> aEntry )
{
m_func = aEntry;
}
/* Function Call()
*
* Starts execution of a coroutine, passing args as its arguments.
* @return true, if the coroutine has yielded and false if it has finished its
* execution (returned).
*/
bool Call( ArgType args )
{
// fixme: Clean up stack stuff. Add a guard
}
/**
* Function Yield()
*
* Stops execution of the coroutine and returns control to the caller.
* After a yield, Call() or Resume() methods invoked by the caller will
* immediately return true, indicating that we are not done yet, just asleep.
*/
void Yield()
{
boost::context::jump_fcontext( m_self, m_saved, 0 );
}
/**
* Function Yield()
*
* Yield with a value - passes a value of given type to the caller.
* Useful for implementing generator objects.
*/
void Yield( ReturnType& retVal )
{
m_retVal = retVal;
boost::context::jump_fcontext( m_self, m_saved, 0 );
}
/**
<F11>* Function SetEntry()
*
* Defines the entry point for the coroutine, if not set in the constructor.
*/
void SetEntry( DELEGATE<ReturnType, ArgType> aEntry )
{
m_func = aEntry;
}
/* Function Call()
*
* Starts execution of a coroutine, passing args as its arguments.
* @return true, if the coroutine has yielded and false if it has finished its
* execution (returned).
*/
bool Call( ArgType args )
{
// fixme: Clean up stack stuff. Add a guard
m_stack = malloc( c_defaultStackSize );
// align to 16 bytes
......@@ -145,87 +145,87 @@ public:
// off we go!
boost::context::jump_fcontext( m_saved, m_self, reinterpret_cast<intptr_t>( this ) );
return m_running;
}
/**
* Function Resume()
*
* Resumes execution of a previously yielded coroutine.
* @return true, if the coroutine has yielded again and false if it has finished its
* execution (returned).
*/
bool Resume()
{
}
/**
* Function Resume()
*
* Resumes execution of a previously yielded coroutine.
* @return true, if the coroutine has yielded again and false if it has finished its
* execution (returned).
*/
bool Resume()
{
boost::context::jump_fcontext( m_saved, m_self, 0 );
return m_running;
}
/**
* Function ReturnValue()
*
* Returns the yielded value (the argument Yield() was called with)
*/
const ReturnType& ReturnValue() const
{
return m_retVal;
}
/**
* Function Running()
*
* @return true, if the coroutine is active
*/
bool Running() const
{
return m_running;
}
}
/**
* Function ReturnValue()
*
* Returns the yielded value (the argument Yield() was called with)
*/
const ReturnType& ReturnValue() const
{
return m_retVal;
}
/**
* Function Running()
*
* @return true, if the coroutine is active
*/
bool Running() const
{
return m_running;
}
private:
static const int c_defaultStackSize = 2000000; // fixme: make configurable
/* real entry point of the coroutine */
static void callerStub( intptr_t data )
{
// get pointer to self
COROUTINE<ReturnType, ArgType>* cor = reinterpret_cast<COROUTINE<ReturnType, ArgType>*>( data );
// call the coroutine method
cor->m_retVal = cor->m_func( *cor->m_args );
cor->m_running = false;
// go back to wherever we came from.
boost::context::jump_fcontext( cor->m_self, cor->m_saved, 0 ); //reinterpret_cast<intptr_t>( this ));
}
template <typename T> struct strip_ref
{
typedef T result;
};
template <typename T> struct strip_ref<T&>
{
typedef T result;
};
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
void* m_stack;
size_t m_stackSize;
bool m_running;
static const int c_defaultStackSize = 2000000; // fixme: make configurable
/* real entry point of the coroutine */
static void callerStub( intptr_t data )
{
// get pointer to self
COROUTINE<ReturnType, ArgType>* cor = reinterpret_cast<COROUTINE<ReturnType, ArgType>*>( data );
// call the coroutine method
cor->m_retVal = cor->m_func( *cor->m_args );
cor->m_running = false;
// go back to wherever we came from.
boost::context::jump_fcontext( cor->m_self, cor->m_saved, 0 ); //reinterpret_cast<intptr_t>( this ));
}
template <typename T> struct strip_ref
{
typedef T result;
};
template <typename T> struct strip_ref<T&>
{
typedef T result;
};
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
void* m_stack;
size_t m_stackSize;
bool m_running;
};
#endif
......@@ -28,38 +28,38 @@
/**
* 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.
*/
template<class ReturnType, class Arg>
class DELEGATE {
public:
typedef ReturnType (DELEGATE<ReturnType, Arg>::*MemberPointer)( Arg );
typedef ReturnType _ReturnType;
typedef Arg _ArgType;
DELEGATE ()
{
}
template<class T>
DELEGATE ( T* object, ReturnType (T::*ptr)( Arg ) )
{
m_ptr = reinterpret_cast<MemberPointer>( ptr );
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:
MemberPointer m_ptr;
void *m_object;
class DELEGATE {
public:
typedef ReturnType (DELEGATE<ReturnType, Arg>::*MemberPointer)( Arg );
typedef ReturnType _ReturnType;
typedef Arg _ArgType;
DELEGATE ()
{
}
template<class T>
DELEGATE ( T* object, ReturnType (T::*ptr)( Arg ) )
{
m_ptr = reinterpret_cast<MemberPointer>( ptr );
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:
MemberPointer m_ptr;
void *m_object;
};
/**
......@@ -67,32 +67,32 @@ private:
* Same as DELEGATE, but with no arguments.
*/
template<class ReturnType>
class DELEGATE0 {
public:
typedef ReturnType ( DELEGATE0<ReturnType>::*MemberPointer )();
typedef ReturnType _ReturnType;
DELEGATE0 ()
{
}
template<class T>
DELEGATE0 ( T* object, ReturnType (T::*ptr)( ) )
{
m_ptr = reinterpret_cast<MemberPointer>( ptr );
m_object = reinterpret_cast<void*>( object );
};
ReturnType operator()( ) const
{
DELEGATE0<ReturnType>* casted = reinterpret_cast<DELEGATE0<ReturnType>*>( m_object );
return ( casted->*m_ptr )();
}
private:
MemberPointer m_ptr;
void *m_object;
class DELEGATE0 {
public:
typedef ReturnType ( DELEGATE0<ReturnType>::*MemberPointer )();
typedef ReturnType _ReturnType;
DELEGATE0 ()
{
}
template<class T>
DELEGATE0 ( T* object, ReturnType (T::*ptr)( ) )
{
m_ptr = reinterpret_cast<MemberPointer>( ptr );
m_object = reinterpret_cast<void*>( object );
};
ReturnType operator()( ) const
{
DELEGATE0<ReturnType>* casted = reinterpret_cast<DELEGATE0<ReturnType>*>( m_object );
return ( casted->*m_ptr )();
}
private:
MemberPointer m_ptr;
void *m_object;
};
#endif
......@@ -9,40 +9,40 @@ typedef COROUTINE<int, int> MyCoroutine;
class MyClass {
public:
int CountTo(int 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++)
{
printf("%s: Yielding %d\n", __FUNCTION__, i);
cofunc.Yield(i);
}
}
void Run()
{
cofunc = MyCoroutine (this, &MyClass::CountTo);
printf("%s: Calling coroutine that will count from 1 to 5.\n", __FUNCTION__);
cofunc.Call(5);
while (cofunc.Running())
{
printf("%s: Got value: %d\n", __FUNCTION__, cofunc.ReturnValue());
cofunc.Resume();
}
printf("%s: Done!\n", __FUNCTION__);
}
MyCoroutine cofunc;
public:
int CountTo(int 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++)
{
printf("%s: Yielding %d\n", __FUNCTION__, i);
cofunc.Yield(i);
}
}
void Run()
{
cofunc = MyCoroutine (this, &MyClass::CountTo);
printf("%s: Calling coroutine that will count from 1 to 5.\n", __FUNCTION__);
cofunc.Call(5);
while (cofunc.Running())
{
printf("%s: Got value: %d\n", __FUNCTION__, cofunc.ReturnValue());
cofunc.Resume();
}
printf("%s: Done!\n", __FUNCTION__);
}
MyCoroutine cofunc;
};
main()
{
MyClass obj;
MyClass obj;
obj.Run();
return 0;
}
obj.Run();
return 0;
}
......@@ -7,29 +7,29 @@ using namespace std;
class MyClass {
public:
int MyMethod(const string &arg)
{
printf("MyClass(this = %p)::MyMethod() called with string '%s', length %d\n", this, arg.c_str(), arg.length());
return arg.length();
}
public:
int MyMethod(const string &arg)
{
printf("MyClass(this = %p)::MyMethod() called with string '%s', length %d\n", this, arg.c_str(), arg.length());
return arg.length();
}
};
typedef DELEGATE<int, const string&> MyDelegate;
main()
{
MyClass t1;
MyClass t2;
MyDelegate ptr1 (&t1, &MyClass::MyMethod);
MyDelegate ptr2 (&t2, &MyClass::MyMethod);
int retval1, retval2;
MyClass t1;
MyClass t2;
MyDelegate ptr1 (&t1, &MyClass::MyMethod);
MyDelegate ptr2 (&t2, &MyClass::MyMethod);
int retval1, retval2;
retval1 = ptr1("apples");
retval2 = ptr2("cherries");
printf("Object 1 returned %d, object 2 returned %d\n", retval1, retval2);
return 0;
}
printf("Object 1 returned %d, object 2 returned %d\n", retval1, retval2);
return 0;
}
......@@ -59,128 +59,128 @@ typedef DELEGATE<int, TOOL_EVENT&> TOOL_STATE_FUNC;
* Base abstract interface for all kinds of tools.
*/
class TOOL_BASE
class TOOL_BASE
{
public:
TOOL_BASE( TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string( "" ) ) :
m_type( aType ),
m_toolId( aId ),
m_toolName( aName ),
m_toolMgr( NULL ){};
virtual ~TOOL_BASE() {};
/**
* Function GetType()
* Returns the type of the tool.
* @return The type of the tool.
*/
TOOL_Type GetType() const
{
return m_type;
}
/**
* Function GetId()
* Returns the unique identifier of the tool. The identifier is set by an instance of
* TOOL_MANAGER.
* @return Identifier of the tool.
*/
TOOL_ID GetId() const
{
return m_toolId;
}
/**
* Function GetName()
* Returns the name of the tool. Tool names are expected to obey the format:
* application.ToolName (eg. pcbnew.InteractiveSelection).
* @return The name of the tool.
*/
const std::string& GetName() const
{
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;
}
TOOL_BASE( TOOL_Type aType, TOOL_ID aId, const std::string& aName = std::string( "" ) ) :
m_type( aType ),
m_toolId( aId ),
m_toolName( aName ),
m_toolMgr( NULL ){};
virtual ~TOOL_BASE() {};
/**
* Function GetType()
* Returns the type of the tool.
* @return The type of the tool.
*/
TOOL_Type GetType() const
{
return m_type;
}
/**
* Function GetId()
* Returns the unique identifier of the tool. The identifier is set by an instance of
* TOOL_MANAGER.
* @return Identifier of the tool.
*/
TOOL_ID GetId() const
{
return m_toolId;
}
/**
* Function GetName()
* Returns the name of the tool. Tool names are expected to obey the format:
* application.ToolName (eg. pcbnew.InteractiveSelection).
* @return The name of the tool.
*/
const std::string& GetName() const
{
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;
}
protected:
friend class TOOL_MANAGER;
/**
* Function attachManager()
*
* Sets the TOOL_MANAGER the tool will belong to.
* Called by TOOL_MANAGER::RegisterTool()
*/
void attachManager( TOOL_MANAGER* aManager );
/**
* Function getView()
*
* Returns the instance of VIEW object used in the application. It allows tools to draw.
* @return The instance of VIEW.
*/
KiGfx::VIEW* getView() const;
/**
* Function getViewControls()
*
* 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.)
* @return The instance of VIEW_CONTROLS.
*/
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()
*
* Returns the model object if it matches the requested type.
*/
template<typename T>
T* getModel( KICAD_T modelType ) const
{
EDA_ITEM* m = getModelInt();
return static_cast<T*>( m );
}
///> Stores the type of the tool.
TOOL_Type m_type;
///> Unique identifier for the tool, assigned by a TOOL_MANAGER instance.
TOOL_ID m_toolId;
///> Name of the tool. Names are expected to obey the format application.ToolName
///> (eg. pcbnew.InteractiveSelection).
std::string m_toolName;
TOOL_MANAGER* m_toolMgr;
friend class TOOL_MANAGER;
/**
* Function attachManager()
*
* Sets the TOOL_MANAGER the tool will belong to.
* Called by TOOL_MANAGER::RegisterTool()
*/
void attachManager( TOOL_MANAGER* aManager );
/**
* Function getView()
*
* Returns the instance of VIEW object used in the application. It allows tools to draw.
* @return The instance of VIEW.
*/
KiGfx::VIEW* getView() const;
/**
* Function getViewControls()
*
* 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.)
* @return The instance of VIEW_CONTROLS.
*/
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()
*
* Returns the model object if it matches the requested type.
*/
template<typename T>
T* getModel( KICAD_T modelType ) const
{
EDA_ITEM* m = getModelInt();
return static_cast<T*>( m );
}
///> Stores the type of the tool.
TOOL_Type m_type;
///> Unique identifier for the tool, assigned by a TOOL_MANAGER instance.
TOOL_ID m_toolId;
///> 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:
// hide the implementation to avoid spreading half of
// kicad and wxWidgets headers to the tools that may not need them at all!
EDA_ITEM* getModelInt() const;
wxWindow* getEditFrameInt() const;
// hide the implementation to avoid spreading half of
// kicad and wxWidgets headers to the tools that may not need them at all!
EDA_ITEM* getModelInt() const;
wxWindow* getEditFrameInt() const;
};
#endif
......@@ -33,12 +33,12 @@ class TOOL_MANAGER;
class PCB_BASE_FRAME;
namespace KiGfx {
class VIEW;
class VIEW;
};
/**
/**
* Class TOOL_DISPATCHER
*
*
* - takes wx events,
* - fixes all wx quirks (mouse warping, panning, ordering problems, etc)
* - translates coordinates to world space
......
......@@ -42,63 +42,63 @@ class TOOL_MANAGER;
*/
enum TOOL_EventCategory
{
TC_None = 0x00,
TC_Mouse = 0x01,
TC_Keyboard = 0x02,
TC_Command = 0x04,
TC_Message = 0x08,
TC_View = 0x10,
TC_Any = 0xffffffff
TC_None = 0x00,
TC_Mouse = 0x01,
TC_Keyboard = 0x02,
TC_Command = 0x04,
TC_Message = 0x08,
TC_View = 0x10,
TC_Any = 0xffffffff
};
enum TOOL_Actions
{
// UI input events
TA_None = 0x0000,
TA_MouseClick = 0x0001,
TA_MouseUp = 0x0002,
TA_MouseDown = 0x0004,
TA_MouseDrag = 0x0008,
TA_MouseMotion = 0x0010,
TA_MouseWheel = 0x0020,
TA_Mouse = 0x003f,
TA_KeyUp = 0x0040,
TA_None = 0x0000,
TA_MouseClick = 0x0001,
TA_MouseUp = 0x0002,
TA_MouseDown = 0x0004,
TA_MouseDrag = 0x0008,
TA_MouseMotion = 0x0010,
TA_MouseWheel = 0x0020,
TA_Mouse = 0x003f,
TA_KeyUp = 0x0040,
TA_KeyDown = 0x0080,
TA_Keyboard = TA_KeyUp | TA_KeyDown,
// View related events
TA_ViewRefresh = 0x0100,
TA_ViewZoom = 0x0200,
TA_ViewPan = 0x0400,
TA_ViewDirty = 0x0800,
TA_ChangeLayer = 0x1000,
TA_ViewRefresh = 0x0100,
TA_ViewZoom = 0x0200,
TA_ViewPan = 0x0400,
TA_ViewDirty = 0x0800,
TA_ChangeLayer = 0x1000,
// Tool cancel event. Issued automagically when the user hits escape or selects End Tool from
// the context menu.
TA_CancelTool = 0x2000,
// Tool cancel event. Issued automagically when the user hits escape or selects End Tool from
// the context menu.
TA_CancelTool = 0x2000,
// 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
TA_ContextMenuUpdate = 0x4000,
// 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
TA_ContextMenuUpdate = 0x4000,
// Context menu choice. Sent if the user picked something from the context menu or
// closed it without selecting anything.
TA_ContextMenuChoice = 0x8000,
// Context menu choice. Sent if the user picked something from the context menu or
// closed it without selecting anything.
TA_ContextMenuChoice = 0x8000,
// Tool action (allows to control tools)
TA_Action = 0x10000,
// Tool action (allows to control tools)
TA_Action = 0x10000,
TA_Any = 0xffffffff
TA_Any = 0xffffffff
};
enum TOOL_MouseButtons
{
MB_None = 0x0,
MB_Left = 0x1,
MB_Right = 0x2,
MB_Middle = 0x4,
MB_ButtonMask = MB_Left | MB_Right | MB_Middle,
MB_Any = 0xffffffff
MB_None = 0x0,
MB_Left = 0x1,
MB_Right = 0x2,
MB_Middle = 0x4,
MB_ButtonMask = MB_Left | MB_Right | MB_Middle,
MB_Any = 0xffffffff
};
enum TOOL_Modifiers
......@@ -120,14 +120,14 @@ enum TOOL_ActionScope
/// Defines when a context menu is opened.
enum CONTEXT_MENU_TRIGGER
{
CMENU_BUTTON = 0, // On the right button
CMENU_NOW, // Right now (after TOOL_INTERACTIVE::SetContextMenu)
CMENU_OFF // Never
CMENU_BUTTON = 0, // On the right button
CMENU_NOW, // Right now (after TOOL_INTERACTIVE::SetContextMenu)
CMENU_OFF // Never
};
/**
/**
* Class TOOL_EVENT
*
*
* Generic, UI-independent tool event.
*/
class TOOL_EVENT
......@@ -359,9 +359,9 @@ private:
typedef boost::optional<TOOL_EVENT> OPT_TOOL_EVENT;
/**
/**
* Class TOOL_EVENT_LIST
*
*
* A list of TOOL_EVENTs, with overloaded || operators allowing for
* 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 )
{
TOOL_EVENT_LIST l;
TOOL_EVENT_LIST l;
l.Add( a );
l.Add( b );
l.Add( a );
l.Add( b );
return l;
return l;
}
inline const TOOL_EVENT_LIST operator||( const TOOL_EVENT& a, const TOOL_EVENT_LIST& b )
{
TOOL_EVENT_LIST l( b );
l.Add( a );
return l;
TOOL_EVENT_LIST l( b );
l.Add( a );
return l;
}
#endif
......@@ -39,23 +39,23 @@ public:
* Constructor
*
* Creates a tool with given id & name. The name must be unique. */
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()
* 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;
/**
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()
* 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()
* Init() is called once upon a registration of the tool.
*
......@@ -66,58 +66,58 @@ public:
return true;
}
/**
* Function SetContextMenu()
*
* Assigns a context menu and tells when it should be activated.
* @param aMenu is the menu to be assigned.
* @param aTrigger determines conditions upon which the context menu is activated.
*/
void SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger = CMENU_BUTTON );
/**
* Function Go()
*
* Defines which state (aStateFunc) to go when a certain event arrives (aConditions).
* No conditions means any event.
*/
template<class T>
void Go( int (T::*aStateFunc)( TOOL_EVENT& ),
const TOOL_EVENT_LIST& aConditions = TOOL_EVENT( TC_Any, TA_Any ) );
/**
* Function Wait()
*
* Suspends execution of the tool until an event specified in aEventList arrives.
* No parameters means waiting for any event.
*/
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 */
/*template<class Parameters, class ReturnValue>
bool InvokeTool( const std::string& aToolName, const Parameters& parameters,
ReturnValue& returnValue );
template<class Parameters, class ReturnValue>
bool InvokeWindow( const std::string& aWindowName, const Parameters& parameters,
ReturnValue& returnValue );
template<class T>
void Yield( const T& returnValue );*/
/**
* Function SetContextMenu()
*
* Assigns a context menu and tells when it should be activated.
* @param aMenu is the menu to be assigned.
* @param aTrigger determines conditions upon which the context menu is activated.
*/
void SetContextMenu( CONTEXT_MENU* aMenu, CONTEXT_MENU_TRIGGER aTrigger = CMENU_BUTTON );
/**
* Function Go()
*
* Defines which state (aStateFunc) to go when a certain event arrives (aConditions).
* No conditions means any event.
*/
template<class T>
void Go( int (T::*aStateFunc)( TOOL_EVENT& ),
const TOOL_EVENT_LIST& aConditions = TOOL_EVENT( TC_Any, TA_Any ) );
/**
* Function Wait()
*
* Suspends execution of the tool until an event specified in aEventList arrives.
* No parameters means waiting for any event.
*/
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 */
/*template<class Parameters, class ReturnValue>
bool InvokeTool( const std::string& aToolName, const Parameters& parameters,
ReturnValue& returnValue );
template<class Parameters, class ReturnValue>
bool InvokeWindow( const std::string& aWindowName, const Parameters& parameters,
ReturnValue& returnValue );
template<class T>
void Yield( const T& returnValue );*/
protected:
/* helper functions for constructing events for Wait() and Go() with less typing */
const TOOL_EVENT evActivate( std::string aToolName = "" );
const TOOL_EVENT evCommand( int aCommandId = -1 );
const TOOL_EVENT evCommand( std::string aCommandStr = "" );
const TOOL_EVENT evMotion();
const TOOL_EVENT evClick( int aButton = MB_Any );
const TOOL_EVENT evDrag( int aButton = MB_Any );
const TOOL_EVENT evButtonUp( int aButton = MB_Any );
const TOOL_EVENT evButtonDown(int aButton = MB_Any );
/* helper functions for constructing events for Wait() and Go() with less typing */
const TOOL_EVENT evActivate( std::string aToolName = "" );
const TOOL_EVENT evCommand( int aCommandId = -1 );
const TOOL_EVENT evCommand( std::string aCommandStr = "" );
const TOOL_EVENT evMotion();
const TOOL_EVENT evClick( int aButton = MB_Any );
const TOOL_EVENT evDrag( int aButton = MB_Any );
const TOOL_EVENT evButtonUp( int aButton = MB_Any );
const TOOL_EVENT evButtonDown(int aButton = MB_Any );
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
......@@ -125,8 +125,8 @@ template<class T>
void TOOL_INTERACTIVE::Go( int (T::*aStateFunc)( TOOL_EVENT& ),
const TOOL_EVENT_LIST& aConditions )
{
TOOL_STATE_FUNC sptr( static_cast<T*>( this ), aStateFunc );
goInternal( sptr, aConditions );
TOOL_STATE_FUNC sptr( static_cast<T*>( this ), aStateFunc );
goInternal( sptr, aConditions );
}
#endif
......@@ -122,7 +122,7 @@ public:
virtual const VECTOR2D GetCursorPosition() const = 0;
/**
/**
* Function ForceCursorPosition()
* Places the cursor immediately at a given point. Mouse movement is ignored.
* @param aEnabled enable forced cursor position
......
File mode changed from 100755 to 100644
......@@ -279,7 +279,7 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
NETINFO_ITEM* net = ( (BOARD*) aTrack->GetParent() )->FindNet( netNumber );
if( !net )
return;
std::string netName = std::string( net->GetShortNetname().mb_str() );
VECTOR2D textPosition = start + line / 2.0; // center of the track
double textOrientation = -atan( line.y / line.x );
......
......@@ -28,7 +28,7 @@
/**
* 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.
**/
......
......@@ -32,9 +32,9 @@
/**
* 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.
* 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.
**/
class PNS_JOINT : public PNS_ITEM
......@@ -53,8 +53,8 @@ public:
PNS_JOINT() :
PNS_ITEM( JOINT ) {}
PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
int aNet = -1 ) :
PNS_JOINT( const VECTOR2I& aPos, const PNS_LAYERSET& aLayers,
int aNet = -1 ) :
PNS_ITEM( JOINT )
{
m_tag.pos = aPos;
......@@ -78,14 +78,14 @@ public:
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.
bool IsLineCorner() const
{
if( m_linkedItems.size() != 2 )
return false;
if( m_linkedItems[0]->GetKind() != SEGMENT ||
if( m_linkedItems[0]->GetKind() != SEGMENT ||
m_linkedItems[1]->GetKind() != SEGMENT )
return false;
......@@ -99,7 +99,7 @@ public:
///> Links the joint to a given board item (when it's added to the PNS_NODE)
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 );
if( f != m_linkedItems.end() )
......@@ -112,7 +112,7 @@ public:
///> Returns true if the joint became dangling after unlinking.
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 );
if( f != m_linkedItems.end() )
......@@ -142,7 +142,7 @@ public:
{
int n = 0;
for( LinkedItems::const_iterator i = m_linkedItems.begin();
for( LinkedItems::const_iterator i = m_linkedItems.begin();
i != m_linkedItems.end(); ++i )
if( (*i)->GetKind() & aMask )
n++;
......@@ -172,7 +172,7 @@ public:
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 );
}
......@@ -186,7 +186,7 @@ private:
// 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 )
{
return p1.pos == p2.pos && p1.net == p2.net;
......
......@@ -434,7 +434,7 @@ void PNS_LINE::NewWalkaround( const SHAPE_LINE_CHAIN& aObstacle,
path.Append( l_hull.CPoint( j ) );
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]) )
break;
}
......@@ -514,7 +514,7 @@ bool PNS_LINE::walkScan( const SHAPE_LINE_CHAIN& line,
{
index_l = (reverse ? sc - 1 - i : i);
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 );
return true;
}
......@@ -523,7 +523,7 @@ bool PNS_LINE::walkScan( const SHAPE_LINE_CHAIN& line,
{
index_l = (reverse ? sc - 1 - i - 1 : i + 1);
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 );
return true;
}
......@@ -562,7 +562,7 @@ bool PNS_LINE::Walkaround( SHAPE_LINE_CHAIN obstacle,
if( line.SegmentCount() < 1 )
return false;
if( obstacle.PointInside( line.CPoint( 0 ) ) ||
if( obstacle.PointInside( line.CPoint( 0 ) ) ||
obstacle.PointInside( line.CPoint( -1 ) ) )
return false;
......@@ -714,7 +714,7 @@ bool PNS_LINE::Is45Degree()
const SEG& s = m_line.CSegment( i );
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 );
if( angle < 0 )
......
......@@ -38,17 +38,17 @@ class PNS_VIA;
/**
* Class PNS_LINE
*
* Represents a track on a PCB, connecting two non-trivial joints (that is,
* 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).
* Instead, they are assembled on-the-fly, based on a via/pad/segment that
* Represents a track on a PCB, connecting two non-trivial joints (that is,
* 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).
* Instead, they are assembled on-the-fly, based on a via/pad/segment that
* belongs/begins them.
*
* 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
* 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
* 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.
*/
......@@ -141,7 +141,7 @@ public:
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)
LinkedSegments* GetLinkedSegments()
{
......@@ -157,7 +157,7 @@ public:
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.
const PNS_LINE ClipToNearestObstacle( PNS_NODE* aNode ) const;
......@@ -168,7 +168,7 @@ public:
///> Returns the number of corners of angles specified by mask 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).
///> aPrePath = path from origin to the obstacle
///> aWalkaroundPath = path around the obstacle
......
......@@ -63,7 +63,7 @@ void PNS_LINE_PLACER::ApplySettings( const PNS_ROUTING_SETTINGS& aSettings )
}
void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet,
void PNS_LINE_PLACER::StartPlacement( const VECTOR2I& aStart, int aNet,
int aWidth, int aLayer )
{
m_direction = m_initial_direction;
......@@ -177,14 +177,14 @@ bool PNS_LINE_PLACER::handlePullback()
DIRECTION_45 last_tail( tail.Segment( -1 ) );
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.
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
// (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);
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() );
// 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.
if( n < 2 )
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 );
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
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& 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_UNDEFINED;
......@@ -366,7 +366,7 @@ bool PNS_LINE_PLACER::handleViaPlacement( PNS_LINE& aHead )
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( -1 ) + force );
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 )
{
// 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 );
// 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
// if(PNS_OPTIMIZER::Optimize(&new_head, PNS_OPTIMIZER::MERGE_SEGMENTS))
......
......@@ -39,7 +39,7 @@ class PNS_ROUTER_BASE;
/**
* 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.
*/
......@@ -63,9 +63,9 @@ public:
/**
* Function Route()
*
* 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
* if the trace was stuck somewhere on the way. May call routeStep()
* 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
* if the trace was stuck somewhere on the way. May call routeStep()
* repetitively due to mouse smoothing.
* @param aP ending point of current route.
* @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
///> that has not been settled yet
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)
const PNS_LINE& GetTail() const { return m_tail; }
......@@ -99,9 +99,9 @@ public:
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
void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved,
void GetUpdatedItems( PNS_NODE::ItemVector& aRemoved,
PNS_NODE::ItemVector& aAdded );
///> Toggles the current posture (straight/diagonal) of the trace head.
......@@ -114,30 +114,30 @@ private:
static const double m_shoveLengthThreshold = 1.7;
bool handleViaPlacement( PNS_LINE& aHead );
/**
* 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).
* @return true, if angle (a, b) is obtuse
*/
bool checkObtusity( const SEG& a, const SEG& b ) const;
/**
* 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
* the last segment before the cut.
* @return true if the line has been changed.
*/
bool handleSelfIntersections();
/**
* 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.
* @return true if the line has been changed.
*/
......@@ -146,7 +146,7 @@ private:
/**
* 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.
* @return true, if the line has been changed.
*/
......@@ -155,20 +155,20 @@ private:
/**
* Function reduceTail()
*
* 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
* 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
* that does not collide with anything.
* @param aEnd: current routing destination point.
* @return true if the line has been changed.
*/
bool reduceTail( const VECTOR2I& aEnd );
void fixHeadPosture();
/**
* 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.
* @return true, if the line has been changed.
*/
......@@ -177,12 +177,12 @@ private:
/**
* Function routeHead()
*
* 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
* around all colliding solid or non-movable items. Movable segments are
* 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
* around all colliding solid or non-movable items. Movable segments are
* 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 );
/**
......@@ -197,7 +197,7 @@ private:
///> routing mode (walkaround, shove, etc.)
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
bool m_follow_mouse;
......
......@@ -71,7 +71,7 @@ PNS_NODE::~PNS_NODE()
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 )
if( (*i)->BelongsTo( this ) )
delete *i;
......@@ -111,14 +111,14 @@ PNS_NODE* PNS_NODE::Branch()
child->m_clearanceFunctor = m_clearanceFunctor;
child->m_root = isRoot() ? this : m_root;
// immmediate offspring of the root branch needs not copy anything.
// For the rest, deep-copy joints, overridden item map and pointers
// immmediate offspring of the root branch needs not copy anything.
// For the rest, deep-copy joints, overridden item map and pointers
// to stored items.
if( !isRoot() )
{
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 )
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
struct PNS_NODE::obstacleVisitor
{
......@@ -200,7 +200,7 @@ struct PNS_NODE::obstacleVisitor
if( !aItem->OfKind( m_kindMask ) )
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.
if( m_override && m_override->overrides( aItem ) )
return true;
......@@ -428,8 +428,8 @@ struct hitVisitor
const PNS_ITEMSET PNS_NODE::HitTest( const VECTOR2I& aPoint )
{
PNS_ITEMSET items;
// fixme: we treat a point as an infinitely small circle - this is inefficient.
SHAPE_CIRCLE s( aPoint, 0 );
// fixme: we treat a point as an infinitely small circle - this is inefficient.
SHAPE_CIRCLE s( aPoint, 0 );
hitVisitor visitor( items, aPoint, this );
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 )
{
// 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
if( aItem->BelongsTo( m_root ) && !isRoot() )
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
else if( !aItem->BelongsTo( m_root ) || isRoot() )
m_index->Remove( aItem );
......@@ -948,7 +948,7 @@ void PNS_NODE::Commit( PNS_NODE* aNode )
BOOST_FOREACH( PNS_ITEM * item, aNode->m_override )
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 )
Add( *i );
......
......@@ -79,13 +79,13 @@ struct PNS_OBSTACLE
/**
* 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.
* Features:
* - spatial-indexed container for PCB item shapes
* - collision search (with clearance checking)
* - 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)
**/
......@@ -145,11 +145,11 @@ public:
void Remove( PNS_ITEM* aItem );
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.
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.
PNS_LINE* AssembleLine( PNS_SEGMENT* aSeg,
const OptJoint& a = OptJoint(), const OptJoint& b = OptJoint() );
......@@ -175,15 +175,15 @@ public:
const OptJoint FindJoint( const VECTOR2I& aPos, int aLayer, int aNet );
///> 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 );
///> finds the joints corresponding to the ends of line aLine
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.
void FindConnectedJoints( const PNS_JOINT& aJoint,
void FindConnectedJoints( const PNS_JOINT& aJoint,
std::vector<PNS_JOINT*>& aConnectedJoints );
///> Destroys all child nodes. Applicable only to the root node.
......@@ -201,15 +201,15 @@ private:
PNS_NODE& operator=( const PNS_NODE& b );
///> 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 );
///> 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 );
///> 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 );
///> helpers for adding/removing items
......@@ -231,7 +231,7 @@ private:
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.
bool overrides( PNS_ITEM* aItem ) const
{
......@@ -249,7 +249,7 @@ private:
///> spatial index of all 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.
JointMap m_joints;
......
......@@ -109,7 +109,7 @@ bool PNS_COST_ESTIMATOR::IsBetter( PNS_COST_ESTIMATOR& aOther,
{
if( aOther.m_cornerCost < m_cornerCost && aOther.m_lengthCost < m_lengthCost )
return true;
else if( aOther.m_cornerCost < m_cornerCost * aCornerTollerance && aOther.m_lengthCost <
m_lengthCost * aLengthTollerance )
return true;
......@@ -531,19 +531,19 @@ PNS_OPTIMIZER::BreakoutList PNS_OPTIMIZER::rectBreakouts( int aWidth,
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 ) ) );
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 ) ) );
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 ) ) );
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 ) ) );
}
else
{
// 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 ) ) );
breakouts.push_back( SHAPE_LINE_CHAIN( c, c - d_offset,
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++ )
{
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 );
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(aEnd)
/* if(aEnd)
* PNSDisplayDebugLine (l_best, 6);
* else
* PNSDisplayDebugLine (l_best, 5);*/
......
......@@ -53,7 +53,7 @@
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.
static PNS_ROUTER* theRouter;
......
......@@ -429,7 +429,7 @@ PNS_SHOVE::ShoveStatus PNS_SHOVE::ShoveLines( PNS_LINE* aCurrentHead )
break;
}
/* if(lastWalkSolid == nearest->item)
/* if(lastWalkSolid == nearest->item)
* {
* fail = true;
* break;
......
......@@ -58,7 +58,7 @@ public:
private:
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 );
ShoveStatus shoveSingleLine( PNS_NODE* aNode, PNS_LINE* aCurrent, PNS_LINE* aObstacle,
......
......@@ -74,7 +74,7 @@ PNS_WALKAROUND::WalkaroundStatus PNS_WALKAROUND::singleStep( PNS_LINE& aPath,
}
}
aPath.NewWalkaround( current_obs->hull, path_pre[0], path_walk[0],
aPath.NewWalkaround( current_obs->hull, path_pre[0], path_walk[0],
path_post[0], aWindingDirection );
aPath.NewWalkaround( current_obs->hull, path_pre[1], path_walk[1],
path_post[1], !aWindingDirection );
......
......@@ -72,7 +72,7 @@ public:
m_cursorApproachMode = aEnabled;
}
WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath,
WalkaroundStatus Route( const PNS_LINE& aInitialPath, PNS_LINE& aWalkPath,
bool aOptimize = true );
private:
......
......@@ -100,7 +100,7 @@ int ROUTER_TOOL::getDefaultWidth( int aNetCode )
}
void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth,
void ROUTER_TOOL::getNetclassDimensions( int aNetCode, int& aWidth,
int& aViaDiameter, int& aViaDrill )
{
BOARD* board = getModel<BOARD>( PCB_T );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment