Beef up BOX2's API so it can replace EDA_RECT.
This commit is contained in:
parent
0c8787cbb9
commit
c7036ae076
|
@ -2,7 +2,7 @@
|
||||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
* Copyright (C) 2012-2021 Kicad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 2012-2022 Kicad Developers, see AUTHORS.txt for contributors.
|
||||||
* Copyright (C) 2013 CERN
|
* Copyright (C) 2013 CERN
|
||||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
*
|
*
|
||||||
|
@ -27,13 +27,14 @@
|
||||||
#ifndef __BOX2_H
|
#ifndef __BOX2_H
|
||||||
#define __BOX2_H
|
#define __BOX2_H
|
||||||
|
|
||||||
#include <math/vector2d.h>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
// Needed for the std::optional definition
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include <math/vector2d.h>
|
||||||
|
#include <geometry/eda_angle.h>
|
||||||
|
#include <trigo.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A 2D bounding box built on top of an origin point and size vector.
|
* A 2D bounding box built on top of an origin point and size vector.
|
||||||
*/
|
*/
|
||||||
|
@ -41,15 +42,20 @@ template <class Vec>
|
||||||
class BOX2
|
class BOX2
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef typename Vec::coord_type coord_type;
|
typedef typename Vec::coord_type coord_type;
|
||||||
typedef typename Vec::extended_type ecoord_type;
|
typedef typename Vec::extended_type ecoord_type;
|
||||||
typedef std::numeric_limits<coord_type> coord_limits;
|
typedef std::numeric_limits<coord_type> coord_limits;
|
||||||
|
|
||||||
BOX2() {};
|
BOX2() :
|
||||||
|
m_Pos( 0, 0 ),
|
||||||
|
m_Size( 0, 0 ),
|
||||||
|
m_init( false )
|
||||||
|
{};
|
||||||
|
|
||||||
BOX2( const Vec& aPos, const Vec& aSize = Vec(0, 0) ) :
|
BOX2( const Vec& aPos, const Vec& aSize = Vec(0, 0) ) :
|
||||||
m_Pos( aPos ),
|
m_Pos( aPos ),
|
||||||
m_Size( aSize )
|
m_Size( aSize ),
|
||||||
|
m_init( true )
|
||||||
{
|
{
|
||||||
Normalize();
|
Normalize();
|
||||||
}
|
}
|
||||||
|
@ -58,6 +64,7 @@ public:
|
||||||
{
|
{
|
||||||
m_Pos.x = m_Pos.y = coord_limits::lowest() / 2 + coord_limits::epsilon();
|
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();
|
m_Size.x = m_Size.y = coord_limits::max() - coord_limits::epsilon();
|
||||||
|
m_init = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec Centre() const
|
Vec Centre() const
|
||||||
|
@ -185,29 +192,74 @@ public:
|
||||||
// Compatibility aliases
|
// Compatibility aliases
|
||||||
coord_type GetLeft() const { return GetX(); }
|
coord_type GetLeft() const { return GetX(); }
|
||||||
coord_type GetTop() const { return GetY(); }
|
coord_type GetTop() const { return GetY(); }
|
||||||
void MoveTopTo( coord_type aTop ) { m_Pos.y = aTop; }
|
const Vec GetCenter() const { return Centre(); }
|
||||||
void MoveBottomTo( coord_type aBottom ) { m_Size.y = aBottom - m_Pos.y; }
|
|
||||||
void MoveLeftTo( coord_type aLeft ) { m_Pos.x = aLeft; }
|
|
||||||
void MoveRightTo( coord_type aRight ) { m_Size.x = aRight - m_Pos.x; }
|
|
||||||
|
|
||||||
void SetOrigin( const Vec& pos ) { m_Pos = pos; }
|
/**
|
||||||
void SetOrigin( coord_type x, coord_type y ) { m_Pos.x = x; m_Pos.y = y; }
|
* @return the width or height, whichever is greater.
|
||||||
void SetSize( const Vec& size ) { m_Size = size; }
|
*/
|
||||||
void SetSize( coord_type w, coord_type h ) { m_Size.x = w; m_Size.y = h; }
|
int GetSizeMax() const { return ( m_Size.x > m_Size.y ) ? m_Size.x : m_Size.y; }
|
||||||
void Offset( coord_type dx, coord_type dy ) { m_Pos.x += dx; m_Pos.y += dy; }
|
|
||||||
void Offset( const Vec& offset )
|
void SetOrigin( const Vec& pos )
|
||||||
{
|
{
|
||||||
m_Pos.x += offset.x; m_Pos.y += offset.y;
|
m_Pos = pos;
|
||||||
|
m_init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOrigin( coord_type x, coord_type y )
|
||||||
|
{
|
||||||
|
SetOrigin( Vec( x, y ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSize( const Vec& size )
|
||||||
|
{
|
||||||
|
m_Size = size;
|
||||||
|
m_init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSize( coord_type w, coord_type h )
|
||||||
|
{
|
||||||
|
SetSize( Vec( w, h ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Offset( coord_type dx, coord_type dy )
|
||||||
|
{
|
||||||
|
m_Pos.x += dx;
|
||||||
|
m_Pos.y += dy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Offset( const Vec& offset )
|
||||||
|
{
|
||||||
|
Offset( offset.x, offset.y );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetX( coord_type val )
|
||||||
|
{
|
||||||
|
SetOrigin( val, m_Pos.y );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetY( coord_type val )
|
||||||
|
{
|
||||||
|
SetOrigin( m_Pos.x, val );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWidth( coord_type val )
|
||||||
|
{
|
||||||
|
SetSize( val, m_Size.y );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetHeight( coord_type val )
|
||||||
|
{
|
||||||
|
SetSize( m_Size.x, val );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetEnd( coord_type x, coord_type y )
|
||||||
|
{
|
||||||
|
SetEnd( Vec( x, y ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetX( coord_type val ) { m_Pos.x = val; }
|
|
||||||
void SetY( coord_type val ) { m_Pos.y = val; }
|
|
||||||
void SetWidth( coord_type val ) { m_Size.x = val; }
|
|
||||||
void SetHeight( coord_type val ) { m_Size.y = val; }
|
|
||||||
void SetEnd( coord_type x, coord_type y ) { SetEnd( Vec( x, y ) ); }
|
|
||||||
void SetEnd( const Vec& pos )
|
void SetEnd( const Vec& pos )
|
||||||
{
|
{
|
||||||
m_Size.x = pos.x - m_Pos.x; m_Size.y = pos.y - m_Pos.y;
|
SetSize( pos - m_Pos );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,7 +295,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the intersection of this with another rectangle.
|
* @return true if this rectangle intersects \a aRect.
|
||||||
*/
|
*/
|
||||||
BOX2<Vec> Intersect( const BOX2<Vec>& aRect )
|
BOX2<Vec> Intersect( const BOX2<Vec>& aRect )
|
||||||
{
|
{
|
||||||
|
@ -265,6 +317,78 @@ public:
|
||||||
return BOX2<Vec>( Vec( 0, 0 ), Vec( 0, 0 ) );
|
return BOX2<Vec>( Vec( 0, 0 ), Vec( 0, 0 ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this rectangle intersects a line from \a aPoint1 to \a aPoint2
|
||||||
|
*/
|
||||||
|
bool Intersects( const Vec& aPoint1, const Vec& aPoint2 ) const
|
||||||
|
{
|
||||||
|
Vec point2, point4;
|
||||||
|
|
||||||
|
if( Contains( aPoint1 ) || Contains( aPoint2 ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
point2.x = GetEnd().x;
|
||||||
|
point2.y = GetOrigin().y;
|
||||||
|
point4.x = GetOrigin().x;
|
||||||
|
point4.y = GetEnd().y;
|
||||||
|
|
||||||
|
//Only need to test 3 sides since a straight line can't enter and exit on same side
|
||||||
|
if( SegmentIntersectsSegment( aPoint1, aPoint2, GetOrigin(), point2 ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( SegmentIntersectsSegment( aPoint1, aPoint2, point2, GetEnd() ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if( SegmentIntersectsSegment( aPoint1, aPoint2, GetEnd(), point4 ) )
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this rectangle intersects the circle defined by \a aCenter and \a aRadius.
|
||||||
|
*/
|
||||||
|
bool IntersectsCircle( const Vec& aCenter, const int aRadius ) const
|
||||||
|
{
|
||||||
|
if( !m_init )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Vec closest = ClosestPointTo( aCenter );
|
||||||
|
|
||||||
|
double dx = static_cast<double>( aCenter.x ) - closest.x;
|
||||||
|
double dy = static_cast<double>( aCenter.y ) - closest.y;
|
||||||
|
|
||||||
|
double r = static_cast<double>( aRadius );
|
||||||
|
|
||||||
|
return ( dx * dx + dy * dy ) <= ( r * r );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if this rectangle intersects the edge of a circle defined by \a aCenter
|
||||||
|
* and \a aRadius.
|
||||||
|
*/
|
||||||
|
bool IntersectsCircleEdge( const Vec& aCenter, const int aRadius, const int aWidth ) const
|
||||||
|
{
|
||||||
|
if( !m_init )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
BOX2<Vec> me( *this );
|
||||||
|
me.Normalize(); // ensure size is >= 0
|
||||||
|
|
||||||
|
// Test if the circle intersects at all
|
||||||
|
if( !IntersectsCircle( aCenter, aRadius + aWidth / 2 ) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Vec farpt = FarthestPointTo( aCenter );
|
||||||
|
// Farthest point must be further than the inside of the line
|
||||||
|
double fx = (double) farpt.x;
|
||||||
|
double fy = (double) farpt.y;
|
||||||
|
|
||||||
|
double r = (double) aRadius - (double) aWidth / 2;
|
||||||
|
|
||||||
|
return ( fx * fx + fy * fy ) > ( r * r );
|
||||||
|
}
|
||||||
|
|
||||||
const std::string Format() const
|
const std::string Format() const
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -362,6 +486,18 @@ public:
|
||||||
*/
|
*/
|
||||||
BOX2<Vec>& Merge( const BOX2<Vec>& aRect )
|
BOX2<Vec>& Merge( const BOX2<Vec>& aRect )
|
||||||
{
|
{
|
||||||
|
if( !m_init )
|
||||||
|
{
|
||||||
|
if( aRect.m_init )
|
||||||
|
{
|
||||||
|
m_Pos = aRect.GetPosition();
|
||||||
|
m_Size = aRect.GetSize();
|
||||||
|
m_init = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Normalize(); // ensure width and height >= 0
|
Normalize(); // ensure width and height >= 0
|
||||||
BOX2<Vec> rect = aRect;
|
BOX2<Vec> rect = aRect;
|
||||||
rect.Normalize(); // ensure width and height >= 0
|
rect.Normalize(); // ensure width and height >= 0
|
||||||
|
@ -384,6 +520,14 @@ public:
|
||||||
*/
|
*/
|
||||||
BOX2<Vec>& Merge( const Vec& aPoint )
|
BOX2<Vec>& Merge( const Vec& aPoint )
|
||||||
{
|
{
|
||||||
|
if( !m_init )
|
||||||
|
{
|
||||||
|
m_Pos = aPoint;
|
||||||
|
m_Size = VECTOR2I( 0, 0 );
|
||||||
|
m_init = true;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
Normalize(); // ensure width and height >= 0
|
Normalize(); // ensure width and height >= 0
|
||||||
|
|
||||||
Vec end = GetEnd();
|
Vec end = GetEnd();
|
||||||
|
@ -397,6 +541,57 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful to calculate bounding box of rotated items, when rotation is not cardinal.
|
||||||
|
*
|
||||||
|
* @return the bounding box of this, after rotation.
|
||||||
|
*/
|
||||||
|
const BOX2<Vec> GetBoundingBoxRotated( const VECTOR2I& aRotCenter,
|
||||||
|
const EDA_ANGLE& aAngle ) const
|
||||||
|
{
|
||||||
|
VECTOR2I corners[4];
|
||||||
|
|
||||||
|
// Build the corners list
|
||||||
|
corners[0] = GetOrigin();
|
||||||
|
corners[2] = GetEnd();
|
||||||
|
corners[1].x = corners[0].x;
|
||||||
|
corners[1].y = corners[2].y;
|
||||||
|
corners[3].x = corners[2].x;
|
||||||
|
corners[3].y = corners[0].y;
|
||||||
|
|
||||||
|
// Rotate all corners, to find the bounding box
|
||||||
|
for( int ii = 0; ii < 4; ii++ )
|
||||||
|
RotatePoint( corners[ii], aRotCenter, aAngle );
|
||||||
|
|
||||||
|
// Find the corners bounding box
|
||||||
|
VECTOR2I start = corners[0];
|
||||||
|
VECTOR2I end = corners[0];
|
||||||
|
|
||||||
|
for( int ii = 1; ii < 4; ii++ )
|
||||||
|
{
|
||||||
|
start.x = std::min( start.x, corners[ii].x );
|
||||||
|
start.y = std::min( start.y, corners[ii].y );
|
||||||
|
end.x = std::max( end.x, corners[ii].x );
|
||||||
|
end.y = std::max( end.y, corners[ii].y );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOX2<Vec> bbox;
|
||||||
|
bbox.SetOrigin( start );
|
||||||
|
bbox.SetEnd( end );
|
||||||
|
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mirror the rectangle from the X axis (negate Y pos and size).
|
||||||
|
*/
|
||||||
|
void RevertYAxis()
|
||||||
|
{
|
||||||
|
m_Pos.y = -m_Pos.y;
|
||||||
|
m_Size.y = -m_Size.y;
|
||||||
|
Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the area of the rectangle.
|
* Return the area of the rectangle.
|
||||||
*
|
*
|
||||||
|
@ -479,6 +674,37 @@ public:
|
||||||
return sqrt( SquaredDistance( aBox ) );
|
return sqrt( SquaredDistance( aBox ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the point in this rect that is closest to the provided point
|
||||||
|
*/
|
||||||
|
const Vec ClosestPointTo( const Vec& aPoint ) const
|
||||||
|
{
|
||||||
|
BOX2<Vec> me( *this );
|
||||||
|
|
||||||
|
me.Normalize(); // ensure size is >= 0
|
||||||
|
|
||||||
|
// Determine closest point to the circle centre within this rect
|
||||||
|
coord_type nx = std::max( me.GetLeft(), std::min( aPoint.x, me.GetRight() ) );
|
||||||
|
coord_type ny = std::max( me.GetTop(), std::min( aPoint.y, me.GetBottom() ) );
|
||||||
|
|
||||||
|
return Vec( nx, ny );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the point in this rect that is farthest from the provided point
|
||||||
|
*/
|
||||||
|
const Vec FarthestPointTo( const Vec& aPoint ) const
|
||||||
|
{
|
||||||
|
BOX2<Vec> me( *this );
|
||||||
|
|
||||||
|
me.Normalize(); // ensure size is >= 0
|
||||||
|
|
||||||
|
coord_type fx = std::max( std::abs( aPoint.x - me.GetLeft() ), std::abs( aPoint.x - me.GetRight() ) );
|
||||||
|
coord_type fy = std::max( std::abs( aPoint.y - me.GetTop() ), std::abs( aPoint.y - me.GetBottom() ) );
|
||||||
|
|
||||||
|
return Vec( fx, fy );
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==( const BOX2<Vec>& aOther ) const
|
bool operator==( const BOX2<Vec>& aOther ) const
|
||||||
{
|
{
|
||||||
auto t1 ( *this );
|
auto t1 ( *this );
|
||||||
|
@ -498,8 +724,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Vec m_Pos; // Rectangle Origin
|
Vec m_Pos; // Rectangle Origin
|
||||||
Vec m_Size; // Rectangle Size
|
Vec m_Size; // Rectangle Size
|
||||||
|
|
||||||
|
bool m_init; // Is the rectangle initialized
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Default specializations */
|
/* Default specializations */
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
* Copyright (C) 2018 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||||
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
|
||||||
* Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
|
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -301,14 +301,7 @@ void PCB_MARKER::SetZoom( double aZoomFactor )
|
||||||
|
|
||||||
const EDA_RECT PCB_MARKER::GetBoundingBox() const
|
const EDA_RECT PCB_MARKER::GetBoundingBox() const
|
||||||
{
|
{
|
||||||
EDA_RECT bbox = m_shapeBoundingBox;
|
return GetBoundingBoxMarker();
|
||||||
|
|
||||||
VECTOR2I pos = m_Pos;
|
|
||||||
pos.x += int( bbox.GetOrigin().x * MarkerScale() );
|
|
||||||
pos.y += int( bbox.GetOrigin().y * MarkerScale() );
|
|
||||||
|
|
||||||
return EDA_RECT( pos, wxSize( int( bbox.GetWidth() * MarkerScale() ),
|
|
||||||
int( bbox.GetHeight() * MarkerScale() ) ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue