Improvements when working closer to 32-bit integer limits.
- Changes BOX2 size to extended coordinates. - Adds BOX2ISafe to construct a BOX2I that will fit in int32. - Adds more checks. - Safer computations. Fixes https://gitlab.com/kicad/code/kicad/-/issues/17670
This commit is contained in:
parent
3f32f0c2d8
commit
865e3a9f3c
|
@ -104,7 +104,7 @@ void DS_PROXY_VIEW_ITEM::ViewDraw( int aLayer, VIEW* aView ) const
|
|||
|
||||
buildDrawList( aView, m_properties, &drawList );
|
||||
|
||||
BOX2I viewport( aView->GetViewport().GetOrigin(), aView->GetViewport().GetSize() );
|
||||
BOX2I viewport = BOX2ISafe( aView->GetViewport() );
|
||||
|
||||
// Draw the title block normally even if the view is flipped
|
||||
bool flipped = gal->IsFlippedX();
|
||||
|
|
|
@ -1166,15 +1166,7 @@ void VIEW::Redraw()
|
|||
ToWorld( screenSize ) - ToWorld( VECTOR2D( 0, 0 ) ) );
|
||||
|
||||
rect.Normalize();
|
||||
BOX2I recti( rect.GetPosition(), rect.GetSize() );
|
||||
|
||||
// The view rtree uses integer positions. Large screens can overflow this size so in
|
||||
// this case, simply set the rectangle to the full rtree.
|
||||
if( rect.GetWidth() > std::numeric_limits<int>::max()
|
||||
|| rect.GetHeight() > std::numeric_limits<int>::max() )
|
||||
{
|
||||
recti.SetMaximum();
|
||||
}
|
||||
BOX2I recti = BOX2ISafe( rect );
|
||||
|
||||
redrawRect( recti );
|
||||
|
||||
|
|
|
@ -43,9 +43,11 @@ template <class Vec>
|
|||
class BOX2
|
||||
{
|
||||
public:
|
||||
typedef typename Vec::coord_type coord_type;
|
||||
typedef typename Vec::extended_type ecoord_type;
|
||||
typedef std::numeric_limits<coord_type> coord_limits;
|
||||
typedef typename Vec::coord_type coord_type;
|
||||
typedef typename Vec::extended_type size_type;
|
||||
typedef typename Vec::extended_type ecoord_type;
|
||||
typedef typename VECTOR2<size_type> SizeVec;
|
||||
typedef std::numeric_limits<coord_type> coord_limits;
|
||||
|
||||
BOX2() :
|
||||
m_Pos( 0, 0 ),
|
||||
|
@ -53,25 +55,39 @@ public:
|
|||
m_init( false )
|
||||
{};
|
||||
|
||||
BOX2( const Vec& aPos, const Vec& aSize = Vec(0, 0) ) :
|
||||
BOX2( const Vec& aPos, const SizeVec& aSize = SizeVec(0, 0) ) :
|
||||
m_Pos( aPos ),
|
||||
m_Size( aSize ),
|
||||
m_init( true )
|
||||
{
|
||||
// Range check
|
||||
KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x );
|
||||
KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y );
|
||||
|
||||
Normalize();
|
||||
}
|
||||
|
||||
void SetMaximum()
|
||||
{
|
||||
m_Pos.x = m_Pos.y = coord_limits::lowest() / 2 + coord_limits::epsilon();
|
||||
m_Size.x = m_Size.y = coord_limits::max() - coord_limits::epsilon();
|
||||
if constexpr( std::is_floating_point<coord_type>() )
|
||||
{
|
||||
m_Pos.x = m_Pos.y = coord_limits::lowest() / 2.0;
|
||||
m_Size.x = m_Size.y = coord_limits::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
// We want to be able to invert the box, so don't use lowest()
|
||||
m_Pos.x = m_Pos.y = -coord_limits::max();
|
||||
m_Size.x = m_Size.y = size_type( coord_limits::max() ) + coord_limits::max();
|
||||
}
|
||||
|
||||
m_init = true;
|
||||
}
|
||||
|
||||
Vec Centre() const
|
||||
{
|
||||
return Vec( m_Pos.x + ( m_Size.x / 2 ),
|
||||
m_Pos.y + ( m_Size.y / 2 ) );
|
||||
return Vec( KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x / 2 ),
|
||||
KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y / 2 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -122,13 +138,13 @@ public:
|
|||
if( m_Size.y < 0 )
|
||||
{
|
||||
m_Size.y = -m_Size.y;
|
||||
m_Pos.y -= m_Size.y;
|
||||
m_Pos.y = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) - m_Size.y );
|
||||
}
|
||||
|
||||
if( m_Size.x < 0 )
|
||||
{
|
||||
m_Size.x = -m_Size.x;
|
||||
m_Pos.x -= m_Size.x;
|
||||
m_Pos.x = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) - m_Size.x );
|
||||
}
|
||||
|
||||
return *this;
|
||||
|
@ -177,7 +193,7 @@ public:
|
|||
return Contains( aRect.GetOrigin() ) && Contains( aRect.GetEnd() );
|
||||
}
|
||||
|
||||
const Vec& GetSize() const { return m_Size; }
|
||||
const SizeVec& GetSize() const { return m_Size; }
|
||||
coord_type GetX() const { return m_Pos.x; }
|
||||
coord_type GetY() const { return m_Pos.y; }
|
||||
|
||||
|
@ -185,10 +201,18 @@ public:
|
|||
const Vec& GetPosition() const { return m_Pos; }
|
||||
const Vec GetEnd() const { return Vec( GetRight(), GetBottom() ); }
|
||||
|
||||
coord_type GetWidth() const { return m_Size.x; }
|
||||
coord_type GetHeight() const { return m_Size.y; }
|
||||
coord_type GetRight() const { return m_Pos.x + m_Size.x; }
|
||||
coord_type GetBottom() const { return m_Pos.y + m_Size.y; }
|
||||
size_type GetWidth() const { return m_Size.x; }
|
||||
size_type GetHeight() const { return m_Size.y; }
|
||||
|
||||
coord_type GetRight() const
|
||||
{
|
||||
return KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x );
|
||||
}
|
||||
|
||||
coord_type GetBottom() const
|
||||
{
|
||||
return KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y );
|
||||
}
|
||||
|
||||
// Compatibility aliases
|
||||
coord_type GetLeft() const { return GetX(); }
|
||||
|
@ -211,15 +235,15 @@ public:
|
|||
SetOrigin( Vec( x, y ) );
|
||||
}
|
||||
|
||||
void SetSize( const Vec& size )
|
||||
void SetSize( const SizeVec& size )
|
||||
{
|
||||
m_Size = size;
|
||||
m_init = true;
|
||||
}
|
||||
|
||||
void SetSize( coord_type w, coord_type h )
|
||||
void SetSize( size_type w, size_type h )
|
||||
{
|
||||
SetSize( Vec( w, h ) );
|
||||
SetSize( SizeVec( w, h ) );
|
||||
}
|
||||
|
||||
void Offset( coord_type dx, coord_type dy )
|
||||
|
@ -243,12 +267,12 @@ public:
|
|||
SetOrigin( m_Pos.x, val );
|
||||
}
|
||||
|
||||
void SetWidth( coord_type val )
|
||||
void SetWidth( size_type val )
|
||||
{
|
||||
SetSize( val, m_Size.y );
|
||||
}
|
||||
|
||||
void SetHeight( coord_type val )
|
||||
void SetHeight( size_type val )
|
||||
{
|
||||
SetSize( m_Size.x, val );
|
||||
}
|
||||
|
@ -260,7 +284,7 @@ public:
|
|||
|
||||
void SetEnd( const Vec& pos )
|
||||
{
|
||||
SetSize( pos - m_Pos );
|
||||
SetSize( SizeVec( pos ) - m_Pos );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -278,13 +302,18 @@ public:
|
|||
rect.Normalize(); // ensure size is >= 0
|
||||
|
||||
// calculate the left common area coordinate:
|
||||
int left = std::max( me.m_Pos.x, rect.m_Pos.x );
|
||||
ecoord_type left = std::max( me.m_Pos.x, rect.m_Pos.x );
|
||||
|
||||
// calculate the right common area coordinate:
|
||||
int right = std::min( me.m_Pos.x + me.m_Size.x, rect.m_Pos.x + rect.m_Size.x );
|
||||
ecoord_type right = std::min( ecoord_type( me.m_Pos.x ) + me.m_Size.x,
|
||||
ecoord_type( rect.m_Pos.x ) + rect.m_Size.x );
|
||||
|
||||
// calculate the upper common area coordinate:
|
||||
int top = std::max( me.m_Pos.y, rect.m_Pos.y );
|
||||
ecoord_type top = std::max( me.m_Pos.y, rect.m_Pos.y );
|
||||
|
||||
// calculate the lower common area coordinate:
|
||||
int bottom = std::min( me.m_Pos.y + me.m_Size.y, rect.m_Pos.y + rect.m_Size.y );
|
||||
ecoord_type bottom = std::min( ecoord_type( me.m_Pos.y ) + me.m_Size.y,
|
||||
ecoord_type( rect.m_Pos.y ) + rect.m_Size.y );
|
||||
|
||||
// if a common area exists, it must have a positive (null accepted) size
|
||||
if( left <= right && top <= bottom )
|
||||
|
@ -307,15 +336,20 @@ public:
|
|||
|
||||
Vec topLeft, bottomRight;
|
||||
|
||||
topLeft.x = std::max( me.m_Pos.x, rect.m_Pos.x );
|
||||
bottomRight.x = std::min( me.m_Pos.x + me.m_Size.x, rect.m_Pos.x + rect.m_Size.x );
|
||||
topLeft.y = std::max( me.m_Pos.y, rect.m_Pos.y );
|
||||
bottomRight.y = std::min( me.m_Pos.y + me.m_Size.y, rect.m_Pos.y + rect.m_Size.y );
|
||||
topLeft.x = std::max( me.m_Pos.x, rect.m_Pos.x );
|
||||
|
||||
if ( topLeft.x < bottomRight.x && topLeft.y < bottomRight.y )
|
||||
return BOX2<Vec>( topLeft, bottomRight - topLeft );
|
||||
bottomRight.x = std::min( size_type( me.m_Pos.x ) + me.m_Size.x,
|
||||
size_type( rect.m_Pos.x ) + rect.m_Size.x );
|
||||
|
||||
topLeft.y = std::max( me.m_Pos.y, rect.m_Pos.y );
|
||||
|
||||
bottomRight.y = std::min( size_type( me.m_Pos.y ) + me.m_Size.y,
|
||||
size_type( rect.m_Pos.y ) + rect.m_Size.y );
|
||||
|
||||
if( topLeft.x < bottomRight.x && topLeft.y < bottomRight.y )
|
||||
return BOX2<Vec>( topLeft, SizeVec( bottomRight ) - topLeft );
|
||||
else
|
||||
return BOX2<Vec>( Vec( 0, 0 ), Vec( 0, 0 ) );
|
||||
return BOX2<Vec>( Vec( 0, 0 ), SizeVec( 0, 0 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -400,10 +434,10 @@ public:
|
|||
VECTOR2I corners[4];
|
||||
|
||||
/* Test A : Any corners exist in rotated rect? */
|
||||
corners[0] = m_Pos;
|
||||
corners[1] = m_Pos + VECTOR2I( m_Size.x, 0 );
|
||||
corners[2] = m_Pos + VECTOR2I( m_Size.x, m_Size.y );
|
||||
corners[3] = m_Pos + VECTOR2I( 0, m_Size.y );
|
||||
corners[0] = VECTOR2I( GetLeft(), GetTop() );
|
||||
corners[1] = VECTOR2I( GetRight(), GetTop() );
|
||||
corners[2] = VECTOR2I( GetRight(), GetBottom() );
|
||||
corners[3] = VECTOR2I( GetLeft(), GetBottom() );
|
||||
|
||||
VECTOR2I rCentre = aRect.Centre();
|
||||
|
||||
|
@ -418,8 +452,8 @@ public:
|
|||
}
|
||||
|
||||
/* Test B : Any corners of rotated rect exist in this one? */
|
||||
int w = aRect.GetWidth() / 2;
|
||||
int h = aRect.GetHeight() / 2;
|
||||
int w = KiCheckedCast<ecoord_type, coord_type>( aRect.GetWidth() / 2 );
|
||||
int h = KiCheckedCast<ecoord_type, coord_type>( aRect.GetHeight() / 2 );
|
||||
|
||||
// Construct corners around center of shape
|
||||
corners[0] = VECTOR2I( -w, -h );
|
||||
|
@ -511,14 +545,14 @@ public:
|
|||
if( m_Size.x < -2 * dx )
|
||||
{
|
||||
// Don't allow deflate to eat more width than we have,
|
||||
m_Pos.x += m_Size.x / 2;
|
||||
m_Pos.x = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) + m_Size.x / 2 );
|
||||
m_Size.x = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The inflate is valid.
|
||||
m_Pos.x -= dx;
|
||||
m_Size.x += 2 * dx;
|
||||
m_Size.x += 2 * dx;
|
||||
}
|
||||
}
|
||||
else // size.x < 0:
|
||||
|
@ -526,7 +560,7 @@ public:
|
|||
if( m_Size.x > 2 * dx )
|
||||
{
|
||||
// Don't allow deflate to eat more width than we have,
|
||||
m_Pos.x -= m_Size.x / 2;
|
||||
m_Pos.x = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.x ) - m_Size.x / 2 );
|
||||
m_Size.x = 0;
|
||||
}
|
||||
else
|
||||
|
@ -542,7 +576,7 @@ public:
|
|||
if( m_Size.y < -2 * dy )
|
||||
{
|
||||
// Don't allow deflate to eat more height than we have,
|
||||
m_Pos.y += m_Size.y / 2;
|
||||
m_Pos.y = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) + m_Size.y / 2 );
|
||||
m_Size.y = 0;
|
||||
}
|
||||
else
|
||||
|
@ -557,7 +591,7 @@ public:
|
|||
if( m_Size.y > 2 * dy )
|
||||
{
|
||||
// Don't allow deflate to eat more height than we have,
|
||||
m_Pos.y -= m_Size.y / 2;
|
||||
m_Pos.y = KiCheckedCast<ecoord_type, coord_type>( ecoord_type( m_Pos.y ) - m_Size.y / 2 );
|
||||
m_Size.y = 0;
|
||||
}
|
||||
else
|
||||
|
@ -843,10 +877,10 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
Vec m_Pos; // Rectangle Origin
|
||||
Vec m_Size; // Rectangle Size
|
||||
Vec m_Pos; // Rectangle Origin
|
||||
SizeVec m_Size; // Rectangle Size
|
||||
|
||||
bool m_init; // Is the rectangle initialized
|
||||
bool m_init; // Is the rectangle initialized
|
||||
};
|
||||
|
||||
/* Default specializations */
|
||||
|
@ -856,4 +890,47 @@ typedef BOX2<VECTOR2D> BOX2D;
|
|||
typedef std::optional<BOX2I> OPT_BOX2I;
|
||||
|
||||
|
||||
inline BOX2I BOX2ISafe( const BOX2D& aInput )
|
||||
{
|
||||
constexpr double high = std::numeric_limits<int>::max();
|
||||
constexpr double low = -std::numeric_limits<int>::max();
|
||||
|
||||
int left = (int) std::clamp( aInput.GetLeft(), low, high );
|
||||
int top = (int) std::clamp( aInput.GetTop(), low, high );
|
||||
|
||||
int64_t right = (int64_t) std::clamp( aInput.GetRight(), low, high );
|
||||
int64_t bottom = (int64_t) std::clamp( aInput.GetBottom(), low, high );
|
||||
|
||||
return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
|
||||
}
|
||||
|
||||
|
||||
inline BOX2I BOX2ISafe( const VECTOR2D& aPos, const VECTOR2D& aSize )
|
||||
{
|
||||
constexpr double high = std::numeric_limits<int>::max();
|
||||
constexpr double low = -std::numeric_limits<int>::max();
|
||||
|
||||
int left = (int) std::clamp( aPos.x, low, high );
|
||||
int top = (int) std::clamp( aPos.y, low, high );
|
||||
|
||||
int64_t right = (int64_t) std::clamp( aPos.x + aSize.x, low, high );
|
||||
int64_t bottom = (int64_t) std::clamp( aPos.y + aSize.y, low, high );
|
||||
|
||||
return BOX2I( VECTOR2I( left, top ), VECTOR2L( right - left, bottom - top ) );
|
||||
}
|
||||
|
||||
|
||||
template <typename S, std::enable_if_t<std::is_integral<S>::value, int> = 0>
|
||||
inline BOX2I BOX2ISafe( const VECTOR2I& aPos, const VECTOR2<S>& aSize )
|
||||
{
|
||||
constexpr int64_t high = std::numeric_limits<int>::max();
|
||||
constexpr int64_t low = -std::numeric_limits<int>::max();
|
||||
|
||||
int64_t right = std::clamp( int64_t( aPos.x ) + aSize.x, low, high );
|
||||
int64_t bottom = std::clamp( int64_t( aPos.y ) + aSize.y, low, high );
|
||||
|
||||
return BOX2I( aPos, VECTOR2L( right - aPos.x, bottom - aPos.y ) );
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -76,6 +76,39 @@ template <typename T> inline constexpr T Clamp( const T& lower, const T& value,
|
|||
_Pragma( "GCC diagnostic ignored \"-Wimplicit-int-float-conversion\"" )
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Perform a cast between numerical types. Will clamp the return value to numerical type limits.
|
||||
*
|
||||
* In Debug build an assert fires if will not fit into the return type.
|
||||
*/
|
||||
template <typename in_type = long long int, typename ret_type = int>
|
||||
inline constexpr ret_type KiCheckedCast( in_type v )
|
||||
{
|
||||
if constexpr( std::is_same_v<in_type, long long int> && std::is_same_v<ret_type, int> )
|
||||
{
|
||||
if( v > std::numeric_limits<int>::max() )
|
||||
{
|
||||
kimathLogOverflow( double( v ), typeid( int ).name() );
|
||||
|
||||
return std::numeric_limits<int>::max();
|
||||
}
|
||||
else if( v < std::numeric_limits<int>::lowest() )
|
||||
{
|
||||
kimathLogOverflow( double( v ), typeid( int ).name() );
|
||||
|
||||
return std::numeric_limits<int>::lowest();
|
||||
}
|
||||
|
||||
return int( v );
|
||||
}
|
||||
else
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Round a floating point number to an integer using "round halfway cases away from zero".
|
||||
*
|
||||
|
|
|
@ -584,8 +584,9 @@ std::ostream& operator<<( std::ostream& aStream, const VECTOR2<T>& aVector )
|
|||
}
|
||||
|
||||
/* Default specializations */
|
||||
typedef VECTOR2<double> VECTOR2D;
|
||||
typedef VECTOR2<int> VECTOR2I;
|
||||
typedef VECTOR2<double> VECTOR2D;
|
||||
typedef VECTOR2<int> VECTOR2I;
|
||||
typedef VECTOR2<long long int> VECTOR2L;
|
||||
|
||||
/* KiROUND specialization for vectors */
|
||||
inline VECTOR2I KiROUND( const VECTOR2D& vec )
|
||||
|
|
|
@ -767,7 +767,7 @@ void PCB_PAINTER::renderNetNameForSegment( const SHAPE_SEGMENT& aSeg, const COLO
|
|||
viewport.SetEnd( VECTOR2D( matrix * screenSize ) );
|
||||
viewport.Normalize();
|
||||
|
||||
BOX2I clipBox( viewport.GetOrigin(), viewport.GetSize() );
|
||||
BOX2I clipBox = BOX2ISafe( viewport );
|
||||
SEG visibleSeg( aSeg.GetSeg().A, aSeg.GetSeg().B );
|
||||
|
||||
ClipLine( &clipBox, visibleSeg.A.x, visibleSeg.A.y, visibleSeg.B.x, visibleSeg.B.y );
|
||||
|
|
|
@ -684,9 +684,8 @@ const BOX2I PCB_TRACK::GetBoundingBox() const
|
|||
xmin -= radius;
|
||||
|
||||
// return a rectangle which is [pos,dim) in nature. therefore the +1
|
||||
BOX2I ret( VECTOR2I( xmin, ymin ), VECTOR2I( xmax - xmin + 1, ymax - ymin + 1 ) );
|
||||
|
||||
return ret;
|
||||
return BOX2ISafe( VECTOR2I( xmin, ymin ),
|
||||
VECTOR2L( (int64_t) xmax - xmin + 1, (int64_t) ymax - ymin + 1 ) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -1114,7 +1113,7 @@ double PCB_TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
|
|||
VECTOR2I start( GetStart() );
|
||||
VECTOR2I end( GetEnd() );
|
||||
BOX2D viewport = aView->GetViewport();
|
||||
BOX2I clipBox( viewport.GetOrigin(), viewport.GetSize() );
|
||||
BOX2I clipBox = BOX2ISafe( viewport );
|
||||
|
||||
ClipLine( &clipBox, start.x, start.y, end.x, end.y );
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ using namespace std::placeholders;
|
|||
#include "pns_solid.h"
|
||||
#include "pns_dragger.h"
|
||||
|
||||
const unsigned int PNS::TOOL_BASE::COORDS_PADDING = pcbIUScale.mmToIU( 20 );
|
||||
|
||||
using namespace KIGFX;
|
||||
|
||||
|
@ -321,6 +322,8 @@ void TOOL_BASE::updateStartItem( const TOOL_EVENT& aEvent, bool aIgnorePads )
|
|||
GAL* gal = m_toolMgr->GetView()->GetGAL();
|
||||
VECTOR2I pos = aEvent.HasPosition() ? (VECTOR2I) aEvent.Position() : m_startSnapPoint;
|
||||
|
||||
pos = GetClampedCoords( pos, COORDS_PADDING );
|
||||
|
||||
controls()->ForceCursorPosition( false );
|
||||
m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.DisableGridSnapping() );
|
||||
m_gridHelper->SetSnap( !aEvent.Modifier( MD_SHIFT ) );
|
||||
|
@ -345,7 +348,7 @@ void TOOL_BASE::updateEndItem( const TOOL_EVENT& aEvent )
|
|||
|
||||
controls()->ForceCursorPosition( false );
|
||||
|
||||
VECTOR2I mousePos = controls()->GetMousePosition();
|
||||
VECTOR2I mousePos = GetClampedCoords( controls()->GetMousePosition(), COORDS_PADDING );
|
||||
|
||||
if( m_router->GetState() == ROUTER::ROUTE_TRACK && aEvent.IsDrag() )
|
||||
{
|
||||
|
|
|
@ -80,6 +80,8 @@ protected:
|
|||
ROUTER* m_router;
|
||||
|
||||
bool m_cancelled;
|
||||
|
||||
static const unsigned int COORDS_PADDING; // Padding from coordinates limits for this tool
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -658,7 +658,7 @@ void ROUTER_TOOL::handleCommonEvents( TOOL_EVENT& aEvent )
|
|||
if( aEvent.Category() == TC_VIEW || aEvent.Category() == TC_MOUSE )
|
||||
{
|
||||
BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
|
||||
m_router->SetVisibleViewArea( BOX2I( viewAreaD.GetOrigin(), viewAreaD.GetSize() ) );
|
||||
m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
|
||||
}
|
||||
|
||||
if( !ADVANCED_CFG::GetCfg().m_EnableRouterDump )
|
||||
|
@ -2238,7 +2238,7 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent )
|
|||
}
|
||||
|
||||
GAL* gal = m_toolMgr->GetView()->GetGAL();
|
||||
VECTOR2I p0 = controls()->GetCursorPosition( false );
|
||||
VECTOR2I p0 = GetClampedCoords( controls()->GetCursorPosition( false ), COORDS_PADDING );
|
||||
VECTOR2I p = p0;
|
||||
|
||||
m_gridHelper->SetUseGrid( gal->GetGridSnapping() && !aEvent.DisableGridSnapping() );
|
||||
|
@ -2265,7 +2265,8 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent )
|
|||
if( editFrame->GetMoveWarpsCursor() )
|
||||
tweakedMousePos = footprint->GetPosition(); // Use footprint anchor to warp mouse
|
||||
else
|
||||
tweakedMousePos = controls()->GetCursorPosition(); // Just use current mouse pos
|
||||
tweakedMousePos = GetClampedCoords( controls()->GetCursorPosition(),
|
||||
COORDS_PADDING ); // Just use current mouse pos
|
||||
|
||||
// We tweak the mouse position using the value from above, and then use that as the
|
||||
// start position to prevent the footprint from jumping when we start dragging.
|
||||
|
@ -2317,7 +2318,7 @@ int ROUTER_TOOL::InlineDrag( const TOOL_EVENT& aEvent )
|
|||
|
||||
// Set the initial visible area
|
||||
BOX2D viewAreaD = getView()->GetGAL()->GetVisibleWorldExtents();
|
||||
m_router->SetVisibleViewArea( BOX2I( viewAreaD.GetOrigin(), viewAreaD.GetSize() ) );
|
||||
m_router->SetVisibleViewArea( BOX2ISafe( viewAreaD ) );
|
||||
|
||||
// Send an initial movement to prime the collision detection
|
||||
m_router->Move( p, nullptr );
|
||||
|
@ -2550,7 +2551,8 @@ int ROUTER_TOOL::InlineBreakTrack( const TOOL_EVENT& aEvent )
|
|||
{
|
||||
// If we're here from a hotkey, then get the current mouse position so we know
|
||||
// where to break the track.
|
||||
m_startSnapPoint = snapToItem( m_startItem, controls()->GetCursorPosition() );
|
||||
m_startSnapPoint = snapToItem(
|
||||
m_startItem, GetClampedCoords( controls()->GetCursorPosition(), COORDS_PADDING ) );
|
||||
}
|
||||
|
||||
if( m_startItem && m_startItem->IsLocked() )
|
||||
|
|
|
@ -248,32 +248,34 @@ VECTOR2I EDIT_TOOL::getSafeMovement( const VECTOR2I& aMovement, const BOX2I& aSo
|
|||
{
|
||||
typedef std::numeric_limits<int> coord_limits;
|
||||
|
||||
int max = coord_limits::max();
|
||||
int min = -max;
|
||||
static const double max = coord_limits::max() - (int) COORDS_PADDING;
|
||||
static const double min = -max;
|
||||
|
||||
double left = aBBoxOffset.x + aSourceBBox.GetPosition().x;
|
||||
double top = aBBoxOffset.y + aSourceBBox.GetPosition().y;
|
||||
|
||||
double right = left + aSourceBBox.GetSize().x;
|
||||
double bottom = top + aSourceBBox.GetSize().y;
|
||||
BOX2D testBox( aSourceBBox.GetPosition(), aSourceBBox.GetSize() );
|
||||
testBox.Offset( aBBoxOffset );
|
||||
|
||||
// Do not restrict movement if bounding box is already out of bounds
|
||||
if( left < min || top < min || right > max || bottom > max )
|
||||
if( testBox.GetLeft() < min || testBox.GetTop() < min || testBox.GetRight() > max
|
||||
|| testBox.GetBottom() > max )
|
||||
{
|
||||
return aMovement;
|
||||
}
|
||||
|
||||
// Constrain moving bounding box to coordinates limits
|
||||
VECTOR2D tryMovement( aMovement );
|
||||
VECTOR2D bBoxOrigin( aSourceBBox.GetPosition() + aBBoxOffset );
|
||||
VECTOR2D clampedBBoxOrigin = GetClampedCoords( bBoxOrigin + tryMovement, COORDS_PADDING );
|
||||
testBox.Offset( aMovement );
|
||||
|
||||
tryMovement = clampedBBoxOrigin - bBoxOrigin;
|
||||
if( testBox.GetLeft() < min )
|
||||
testBox.Offset( min - testBox.GetLeft(), 0 );
|
||||
|
||||
VECTOR2D bBoxEnd( aSourceBBox.GetEnd() + aBBoxOffset );
|
||||
VECTOR2D clampedBBoxEnd = GetClampedCoords( bBoxEnd + tryMovement, COORDS_PADDING );
|
||||
if( max < testBox.GetRight() )
|
||||
testBox.Offset( -( testBox.GetRight() - max ), 0 );
|
||||
|
||||
tryMovement = clampedBBoxEnd - bBoxEnd;
|
||||
if( testBox.GetTop() < min )
|
||||
testBox.Offset( 0, min - testBox.GetTop() );
|
||||
|
||||
return GetClampedCoords<double, int>( tryMovement );
|
||||
if( max < testBox.GetBottom() )
|
||||
testBox.Offset( 0, -( testBox.GetBottom() - max ) );
|
||||
|
||||
return KiROUND( testBox.GetPosition() - aBBoxOffset - aSourceBBox.GetPosition() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -407,7 +409,6 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
|||
|
||||
bool restore_state = false;
|
||||
VECTOR2I originalPos;
|
||||
VECTOR2I totalMovement;
|
||||
VECTOR2D bboxMovement;
|
||||
BOX2I originalBBox;
|
||||
bool updateBBox = true;
|
||||
|
@ -493,12 +494,7 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
|||
|
||||
for( EDA_ITEM* item : sel_items )
|
||||
{
|
||||
BOX2I viewBBOX = item->ViewBBox();
|
||||
|
||||
if( originalBBox.GetWidth() == 0 && originalBBox.GetHeight() == 0 )
|
||||
originalBBox = viewBBOX;
|
||||
else
|
||||
originalBBox.Merge( viewBBOX );
|
||||
originalBBox.Merge( item->ViewBBox() );
|
||||
}
|
||||
|
||||
updateBBox = false;
|
||||
|
@ -514,7 +510,6 @@ bool EDIT_TOOL::doMoveSelection( const TOOL_EVENT& aEvent, BOARD_COMMIT* aCommit
|
|||
selection.SetReferencePoint( m_cursor );
|
||||
|
||||
prevPos = m_cursor;
|
||||
totalMovement += movement;
|
||||
bboxMovement += movement;
|
||||
|
||||
// Drag items to the current cursor position
|
||||
|
|
|
@ -2379,8 +2379,8 @@ void PCB_SELECTION_TOOL::FindItem( BOARD_ITEM* aItem )
|
|||
|
||||
KIGFX::PCB_VIEW* pcbView = canvas()->GetView();
|
||||
BOX2D screenBox = pcbView->GetViewport();
|
||||
VECTOR2I screenSize = screenBox.GetSize();
|
||||
BOX2I screenRect( screenBox.GetOrigin(), screenSize / marginFactor );
|
||||
VECTOR2D screenSize = screenBox.GetSize();
|
||||
BOX2I screenRect = BOX2ISafe( screenBox.GetOrigin(), screenSize / marginFactor );
|
||||
|
||||
if( !screenRect.Contains( aItem->GetBoundingBox() ) )
|
||||
{
|
||||
|
@ -3151,7 +3151,7 @@ int PCB_SELECTION_TOOL::hitTestDistance( const VECTOR2I& aWhere, BOARD_ITEM* aIt
|
|||
int aMaxDistance ) const
|
||||
{
|
||||
BOX2D viewportD = getView()->GetViewport();
|
||||
BOX2I viewport( VECTOR2I( viewportD.GetPosition() ), VECTOR2I( viewportD.GetSize() ) );
|
||||
BOX2I viewport = BOX2ISafe( viewportD );
|
||||
int distance = INT_MAX;
|
||||
SEG loc( aWhere, aWhere );
|
||||
|
||||
|
@ -3754,7 +3754,7 @@ void PCB_SELECTION_TOOL::FilterCollectorForFootprints( GENERAL_COLLECTOR& aColle
|
|||
{
|
||||
const RENDER_SETTINGS* settings = getView()->GetPainter()->GetSettings();
|
||||
BOX2D viewport = getView()->GetViewport();
|
||||
BOX2I extents( viewport.GetPosition(), viewport.GetSize() );
|
||||
BOX2I extents = BOX2ISafe( viewport );
|
||||
|
||||
bool need_direct_hit = false;
|
||||
FOOTPRINT* single_fp = nullptr;
|
||||
|
|
Loading…
Reference in New Issue