kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #29329
[FEATURE] Partial selection in pcbnew
I have attached a patch-set that implements "partial selection" of objects
when the selection box is dragged right-to-left.
L -> R = Objects must be completely enclosed to be selected
R -> L = Objects that intersect the selection rectangle will be selected.
To achieve this I had to fix a lot of the HitTest implementations as this
was broken for most shapes, under a variety of edge cases (some HitTest
code did not work at all).
There are two issues I see as outstanding, and am unsure how to proceed:
1. When editing a PCB, selecting part of a footprint (e.g. a line of the
courtyard) selects both that line and the entire footprint. This causes
some issues when the footprint is dragged around the PCB. I believe that
the line should not be selected separately, but the entire footprint should.
2. The inverse of 1. In the footprint editor, selecting a single graphical
item selects the entire footprint. Somehow I would like to filter the
selection such that individual items are selected but NOT the entire
footprint.
Feedback please! :)
I have fixed hit testing (both for wxPoint and EDA_RECT comparison) for:
- Pads (all shapes)
- Lines
- Circles
- Arcs
- Text items
- Zones
- Footprints
Cheers,
Oliver
From 688d986602189b24877dd3296f12d8adb2a5fd9f Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Fri, 21 Apr 2017 00:20:56 +1000
Subject: [PATCH 01/12] Alter selection mode based on drag direction
LEFT > RIGHT = Enclosed selection
RIGHT > LEFT = Touching selection
---
include/preview_items/selection_area.h | 4 ++++
pcbnew/tools/selection_tool.cpp | 37 ++++++++++++++++++++++++++++++----
2 files changed, 37 insertions(+), 4 deletions(-)
diff --git a/include/preview_items/selection_area.h b/include/preview_items/selection_area.h
index c860ee4..d45924b 100644
--- a/include/preview_items/selection_area.h
+++ b/include/preview_items/selection_area.h
@@ -76,6 +76,10 @@ public:
return wxT( "SELECTION_AREA" );
}
+ VECTOR2I GetOrigin() const { return m_origin; }
+
+ VECTOR2I GetEnd() const { return m_end; }
+
private:
/**
diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp
index 494fb1c..d31eee7 100644
--- a/pcbnew/tools/selection_tool.cpp
+++ b/pcbnew/tools/selection_tool.cpp
@@ -500,21 +500,50 @@ bool SELECTION_TOOL::selectMultiple()
// Mark items within the selection box as selected
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
+
+ // Filter the view items based on the selection box
BOX2I selectionBox = area.ViewBBox();
view->Query( selectionBox, selectedItems ); // Get the list of selected items
std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR>::iterator it, it_end;
+ int width = area.GetEnd().x - area.GetOrigin().x;
+ int height = area.GetEnd().y - area.GetOrigin().y;
+
+ // Construct an EDA_RECT to determine BOARD_ITEM selection
+ EDA_RECT selectionRect( wxPoint( area.GetOrigin().x, area.GetOrigin().y ),
+ wxSize( width, height ) );
+
+ selectionRect.Normalize();
+
for( it = selectedItems.begin(), it_end = selectedItems.end(); it != it_end; ++it )
{
BOARD_ITEM* item = static_cast<BOARD_ITEM*>( it->first );
- // Add only those items that are visible and fully within the selection box
- if( !item->IsSelected() && selectable( item ) &&
- selectionBox.Contains( item->ViewBBox() ) )
+ /* Selection mode depends on direction of drag-selection:
+ * Left > Right : Select objects that are fully enclosed by selection
+ * Right > Left : Select objects that are crossed by selection
+ */
+
+ // Add only those items that are visible
+ if( !item->IsSelected() && selectable( item ) )
{
- select( item );
+ if( item->HitTest( selectionRect, width >= 0) )
+ {
+ select( item );
+ }
+
}
+ /*
+ // Selecting left->right requires full enclosure
+ if ( xDelta >= 0 && selectionBox.Contains( item->ViewBBox() ) )
+ {
+ select( item );
+ }
+
+ // Selecting right->left requires only
+ else if
+ */
}
if( m_selection.Size() == 1 )
--
2.7.4
From db7ac6f20c515c590b652284f4a59645f664beb1 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Fri, 21 Apr 2017 00:53:57 +1000
Subject: [PATCH 02/12] Fixed ::HitTest for Circle shape
- Testing against rectangle intersection now works correctly
- Previously tested against BoundingBox() not circle outline
---
common/base_struct.cpp | 60 +++++++++++++++++++++++++++++++++++++++++
include/class_eda_rect.h | 30 +++++++++++++++++++++
pcbnew/class_drawsegment.cpp | 15 ++++++++++-
pcbnew/tools/selection_tool.cpp | 16 +++++------
4 files changed, 110 insertions(+), 11 deletions(-)
diff --git a/common/base_struct.cpp b/common/base_struct.cpp
index 76f51fb..8839ad8 100644
--- a/common/base_struct.cpp
+++ b/common/base_struct.cpp
@@ -443,6 +443,66 @@ bool EDA_RECT::Intersects( const EDA_RECT& aRect ) const
return rc;
}
+const wxPoint EDA_RECT::ClosestPointTo( const wxPoint& aPoint ) const
+{
+ EDA_RECT me(*this);
+
+ me.Normalize(); // ensure size is >= 0
+
+ // Determine closest point to the circle centre within this rect
+ int nx = std::max( me.GetLeft(), std::min( aPoint.x, me.GetRight() ) );
+ int ny = std::max( me.GetTop(), std::min( aPoint.y, me.GetBottom() ) );
+
+ return wxPoint( nx, ny );
+}
+
+const wxPoint EDA_RECT::FarthestPointTo( const wxPoint& aPoint ) const
+{
+ EDA_RECT me(*this);
+
+ me.Normalize(); // ensure size is >= 0
+
+ int fx = std::max( std::abs( aPoint.x - me.GetLeft() ), std::abs( aPoint.x - me.GetRight() ) );
+ int fy = std::max( std::abs( aPoint.y - me.GetTop() ), std::abs( aPoint.y - me.GetBottom() ) );
+
+ return wxPoint( fx, fy );
+}
+
+/* IntersectsCircle
+ * test for common area between this rect and a circle
+ */
+bool EDA_RECT::IntersectsCircle( const wxPoint& aCenter, const int aRadius ) const
+{
+ wxPoint closest = ClosestPointTo( aCenter );
+
+ double dx = aCenter.x - closest.x;
+ double dy = aCenter.y - closest.y;
+
+ double r = (double) aRadius;
+
+ return ( dx * dx + dy * dy ) <= ( r * r );
+}
+
+bool EDA_RECT::IntersectsCircleEdge( const wxPoint& aCenter, const int aRadius, const int aWidth ) const
+{
+ EDA_RECT me(*this);
+ me.Normalize(); // ensure size is >= 0
+
+ // Test if the circle intersects at all
+ if( !IntersectsCircle( aCenter, aRadius + aWidth / 2 ) )
+ {
+ return false;
+ }
+
+ wxPoint far = FarthestPointTo( aCenter );
+ // Farthest point must be further than the inside of the line
+ double fx = (double) far.x;
+ double fy = (double) far.y;
+
+ double r = (double) aRadius - (double) aWidth / 2;
+
+ return ( fx * fx + fy * fy ) > ( r * r );
+}
EDA_RECT& EDA_RECT::Inflate( int aDelta )
{
diff --git a/include/class_eda_rect.h b/include/class_eda_rect.h
index 8849942..d9a67c1 100644
--- a/include/class_eda_rect.h
+++ b/include/class_eda_rect.h
@@ -169,6 +169,36 @@ public:
bool Intersects( const wxPoint& aPoint1, const wxPoint& aPoint2 ) const;
/**
+ * Return the point in this rect that is closest to the provided point
+ */
+ const wxPoint ClosestPointTo( const wxPoint& aPoint ) const;
+
+ /**
+ * Return the point in this rect that is farthest from the provided point
+ */
+ const wxPoint FarthestPointTo( const wxPoint& aPoint ) const;
+
+ /**
+ * Function IntersectsCircle
+ * tests for a common area between a circle and this rectangle
+ *
+ * @param aCenter center of the circle
+ * @param aRadius radius of the circle
+ */
+ bool IntersectsCircle( const wxPoint& aCenter, const int aRadius ) const;
+
+
+ /**
+ * IntersectsCircleEdge
+ * Tests for intersection between this rect and the edge (radius) of a circle
+ *
+ * @param aCenter center of the circle
+ * @param aRadius radius of the circle
+ * @param aWidth width of the circle edge
+ */
+ bool IntersectsCircleEdge( const wxPoint& aCenter, const int aRadius, const int aWidth ) const;
+
+ /**
* Function operator(wxRect)
* overloads the cast operator to return a wxRect
* wxRect does not accept negative values for size, so ensure the
diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp
index 568c8be..89947ae 100644
--- a/pcbnew/class_drawsegment.cpp
+++ b/pcbnew/class_drawsegment.cpp
@@ -522,6 +522,8 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
EDA_RECT arect = aRect;
arect.Inflate( aAccuracy );
+ EDA_RECT arcRect;
+
switch( m_Shape )
{
case S_CIRCLE:
@@ -529,7 +531,18 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
if( aContained )
return arect.Contains( GetBoundingBox() );
else
- return arect.Intersects( GetBoundingBox() );
+ {
+ // If the rectangle does not intersect the bounding box, this is a much quicker test
+ if( !aRect.Intersects( GetBoundingBox() ) )
+ {
+ return false;
+ }
+ else
+ {
+ return arect.IntersectsCircleEdge( GetCenter(), GetRadius(), GetWidth() );
+ }
+
+ }
break;
case S_ARC:
diff --git a/pcbnew/tools/selection_tool.cpp b/pcbnew/tools/selection_tool.cpp
index d31eee7..0ea9529 100644
--- a/pcbnew/tools/selection_tool.cpp
+++ b/pcbnew/tools/selection_tool.cpp
@@ -525,25 +525,21 @@ bool SELECTION_TOOL::selectMultiple()
* Right > Left : Select objects that are crossed by selection
*/
- // Add only those items that are visible
- if( !item->IsSelected() && selectable( item ) )
+ if( width >= 0 )
{
- if( item->HitTest( selectionRect, width >= 0) )
+ if( selectionBox.Contains( item->ViewBBox() ) )
{
select( item );
}
-
}
- /*
- // Selecting left->right requires full enclosure
- if ( xDelta >= 0 && selectionBox.Contains( item->ViewBBox() ) )
+ else
+ {
+ if( item->HitTest( selectionRect, false ) )
{
select( item );
}
- // Selecting right->left requires only
- else if
- */
+ }
}
if( m_selection.Size() == 1 )
--
2.7.4
From 58b8a4be78972b2d2890b4e3ab41024108d160eb Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 22 Apr 2017 15:03:06 +1000
Subject: [PATCH 03/12] Fixed HitTest for Arc segment
---
pcbnew/class_drawsegment.cpp | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp
index 89947ae..c3fab97 100644
--- a/pcbnew/class_drawsegment.cpp
+++ b/pcbnew/class_drawsegment.cpp
@@ -516,9 +516,6 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) const
bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
- wxPoint p1, p2;
- int radius;
- float theta;
EDA_RECT arect = aRect;
arect.Inflate( aAccuracy );
@@ -546,24 +543,28 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
break;
case S_ARC:
- radius = hypot( (double)( GetEnd().x - GetStart().x ),
- (double)( GetEnd().y - GetStart().y ) );
- theta = std::atan2( (double)( GetEnd().y - GetStart().y ),
- (double)( GetEnd().x - GetStart().x ) );
- //Approximate the arc with two lines. This should be accurate enough for selection.
- p1.x = radius * std::cos( theta + M_PI/4 ) + GetStart().x;
- p1.y = radius * std::sin( theta + M_PI/4 ) + GetStart().y;
- p2.x = radius * std::cos( theta + M_PI/2 ) + GetStart().x;
- p2.y = radius * std::sin( theta + M_PI/2 ) + GetStart().y;
+ computeArcBBox( arcRect );
+ // Test for full containment of this arc in the rect
if( aContained )
- return arect.Contains( GetEnd() ) && aRect.Contains( p1 ) && aRect.Contains( p2 );
+ {
+ return arect.Contains( arcRect );
+ }
+ // Test if the rect crosses the arc
else
- return arect.Intersects( GetEnd(), p1 ) || aRect.Intersects( p1, p2 );
-
+ {
+ arcRect = arcRect.Common( arect );
+ //arcRect.Inflate( GetWidth() );
+
+ /* All following tests must pass:
+ * 1. Rectangle must intersect arc BoundingBox
+ * 2. Rectangle must cross the outside of the arc
+ */
+ return arcRect.Intersects( arect ) &&
+ arcRect.IntersectsCircleEdge( GetCenter(), GetRadius(), GetWidth() );
+ }
break;
-
case S_SEGMENT:
if( aContained )
return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
--
2.7.4
From 06ac9516a685e8727085a26e5efd560630a62fbe Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sat, 22 Apr 2017 16:49:15 +1000
Subject: [PATCH 04/12] HitTest for pads
- Circular pads
---
pcbnew/class_drawsegment.cpp | 1 +
pcbnew/class_pad.cpp | 30 ++++++++++++++++++++++++++++++
pcbnew/class_pad.h | 2 ++
3 files changed, 33 insertions(+)
diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp
index c3fab97..53293ff 100644
--- a/pcbnew/class_drawsegment.cpp
+++ b/pcbnew/class_drawsegment.cpp
@@ -517,6 +517,7 @@ bool DRAWSEGMENT::HitTest( const wxPoint& aPosition ) const
bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
EDA_RECT arect = aRect;
+ arect.Normalize();
arect.Inflate( aAccuracy );
EDA_RECT arcRect;
diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp
index 1d2b81a..ba17744 100644
--- a/pcbnew/class_pad.cpp
+++ b/pcbnew/class_pad.cpp
@@ -776,6 +776,36 @@ bool D_PAD::HitTest( const wxPoint& aPosition ) const
return false;
}
+bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
+{
+ EDA_RECT arect = aRect;
+ arect.Normalize();
+ arect.Inflate( aAccuracy );
+
+ if( !arect.Intersects( GetBoundingBox() ) )
+ return false;
+
+ if( aContained )
+ return arect.Contains( GetBoundingBox() );
+
+ switch( GetShape() )
+ {
+ case PAD_SHAPE_CIRCLE:
+ return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
+ case PAD_SHAPE_RECT:
+ break;
+ case PAD_SHAPE_OVAL:
+ break;
+ case PAD_SHAPE_TRAPEZOID:
+ break;
+ case PAD_SHAPE_ROUNDRECT:
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
int D_PAD::Compare( const D_PAD* padref, const D_PAD* padcmp )
{
diff --git a/pcbnew/class_pad.h b/pcbnew/class_pad.h
index 4dd2233..53900dd 100644
--- a/pcbnew/class_pad.h
+++ b/pcbnew/class_pad.h
@@ -483,6 +483,8 @@ public:
bool HitTest( const wxPoint& aPosition ) const override;
+ bool HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy = 0 ) const override;
+
wxString GetClass() const override
{
return wxT( "PAD" );
--
2.7.4
From c47454c352a6f7f74383b7816bd7f2b46a81175c Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sun, 23 Apr 2017 10:06:56 +1000
Subject: [PATCH 05/12] HitTest for Rectangular pads
HitTest for Rectangular pads
- Works at any rotation, even with Shape Offset
- Fixed bugs in D_PAD BoundingBox calculation
---
common/base_struct.cpp | 104 +++++++++++++++++++++++++++++++++++++++++++
include/class_eda_rect.h | 9 ++++
pcbnew/class_drawsegment.cpp | 7 ++-
pcbnew/class_pad.cpp | 30 +++++++++----
4 files changed, 141 insertions(+), 9 deletions(-)
diff --git a/common/base_struct.cpp b/common/base_struct.cpp
index 8839ad8..e44d496 100644
--- a/common/base_struct.cpp
+++ b/common/base_struct.cpp
@@ -443,6 +443,110 @@ bool EDA_RECT::Intersects( const EDA_RECT& aRect ) const
return rc;
}
+bool EDA_RECT::Intersects( const EDA_RECT& aRect, double aRot ) const
+{
+ /* Most rectangles will be axis aligned.
+ * It is quicker to check for this case and pass the rect
+ * to the simpler intersection test
+ */
+
+ // Prevent floating point comparison errors
+ static const double ROT_EPS = 0.000000001;
+
+ static const double ROT_PARALLEL[] = { -3600, -1800, 0, 1800, 3600 };
+ static const double ROT_PERPENDICULAR[] = { -2700, -900, 0, 900, 2700 };
+
+ NORMALIZE_ANGLE_POS<double>( aRot );
+
+ // Test for non-rotated rectangle
+ for( int ii=0; ii<5; ii++ )
+ {
+ if( std::fabs( aRot - ROT_PARALLEL[ii] ) < ROT_EPS )
+ {
+ return Intersects( aRect );
+ }
+ }
+
+ // Test for rectangle rotated by multiple of 90 degrees
+ for( int jj=0; jj<4; jj++ )
+ {
+ if( std::fabs( aRot - ROT_PERPENDICULAR[jj] ) < ROT_EPS )
+ {
+ EDA_RECT rotRect;
+
+ // Rotate the supplied rect by 90 degrees
+ rotRect.SetOrigin( aRect.Centre() );
+ rotRect.Inflate( aRect.GetHeight(), aRect.GetWidth() );
+ return Intersects( rotRect );
+ }
+ }
+
+ /* There is some non-orthogonal rotation.
+ * There are three cases to test:
+ * A) One point of this rect is inside the rotated rect
+ * B) One point of the rotated rect is inside this rect
+ * C) One of the sides of the rotated rect intersect this
+ */
+
+ wxPoint corners[4];
+
+ /* Test A : Any corners exist in rotated rect? */
+
+ corners[0] = m_Pos;
+ corners[1] = m_Pos + wxPoint( m_Size.x, 0 );
+ corners[2] = m_Pos + wxPoint( m_Size.x, m_Size.y );
+ corners[3] = m_Pos + wxPoint( 0, m_Size.y );
+
+ wxPoint rCentre = aRect.Centre();
+
+ for( int i=0; i<4; i++ )
+ {
+ wxPoint delta = corners[i] - rCentre;
+ RotatePoint( &delta, -aRot );
+ delta += rCentre;
+
+ if( aRect.Contains( delta ) )
+ {
+ return true;
+ }
+ }
+
+ /* Test B : Any corners of rotated rect exist in this one? */
+ int w = aRect.GetWidth() / 2;
+ int h = aRect.GetHeight() / 2;
+
+ // Construct corners around center of shape
+ corners[0] = wxPoint( -w, -h );
+ corners[1] = wxPoint( w, -h );
+ corners[2] = wxPoint( w, h );
+ corners[3] = wxPoint( -w, h );
+
+ // Rotate and test each corner
+ for( int j=0; j<4; j++ )
+ {
+ RotatePoint( &corners[j], aRot );
+ corners[j] += rCentre;
+
+ if( Contains( corners[j] ) )
+ {
+ return true;
+ }
+ }
+
+ /* Test C : Any sides of rotated rect intersect this */
+
+ if( Intersects( corners[0], corners[1] ) ||
+ Intersects( corners[1], corners[2] ) ||
+ Intersects( corners[2], corners[3] ) ||
+ Intersects( corners[3], corners[0] ) )
+ {
+ return true;
+ }
+
+
+ return false;
+}
+
const wxPoint EDA_RECT::ClosestPointTo( const wxPoint& aPoint ) const
{
EDA_RECT me(*this);
diff --git a/include/class_eda_rect.h b/include/class_eda_rect.h
index d9a67c1..c14c3b1 100644
--- a/include/class_eda_rect.h
+++ b/include/class_eda_rect.h
@@ -158,6 +158,15 @@ public:
bool Intersects( const EDA_RECT& aRect ) const;
/**
+ * Tests for a common area between this rectangle,
+ * and a rectangle with arbitrary rotation
+ *
+ * @param aRect a rectangle to test intersection with
+ * @param aRot rectangle rotation (in 1/10 degrees)
+ */
+ bool Intersects( const EDA_RECT& aRect, double aRot ) const;
+
+ /**
* Function Intersects
* tests for a common area between a segment and this rectangle.
*
diff --git a/pcbnew/class_drawsegment.cpp b/pcbnew/class_drawsegment.cpp
index 53293ff..30f234a 100644
--- a/pcbnew/class_drawsegment.cpp
+++ b/pcbnew/class_drawsegment.cpp
@@ -556,7 +556,6 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
else
{
arcRect = arcRect.Common( arect );
- //arcRect.Inflate( GetWidth() );
/* All following tests must pass:
* 1. Rectangle must intersect arc BoundingBox
@@ -568,9 +567,15 @@ bool DRAWSEGMENT::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy
break;
case S_SEGMENT:
if( aContained )
+ {
return arect.Contains( GetStart() ) && aRect.Contains( GetEnd() );
+ }
else
+ {
+ // Account for the width of the line
+ arect.Inflate( GetWidth() / 2 );
return arect.Intersects( GetStart(), GetEnd() );
+ }
break;
diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp
index ba17744..64d42c4 100644
--- a/pcbnew/class_pad.cpp
+++ b/pcbnew/class_pad.cpp
@@ -178,6 +178,9 @@ int D_PAD::GetRoundRectCornerRadius( const wxSize& aSize ) const
}
+/**
+ * Return the BoundingBox for a D_PAD
+ */
const EDA_RECT D_PAD::GetBoundingBox() const
{
EDA_RECT area;
@@ -192,7 +195,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
break;
case PAD_SHAPE_OVAL:
- // Calculate the position of each rounded ent
+ // Calculate the position of each rounded end
quadrant1.x = m_Size.x/2;
quadrant1.y = 0;
quadrant2.x = 0;
@@ -207,7 +210,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
// Set the bbox
- area.SetOrigin( m_Pos );
+ area.SetOrigin( ShapePos() );
area.Inflate( dx, dy );
break;
@@ -226,7 +229,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
// Set the bbox
- area.SetOrigin( m_Pos );
+ area.SetOrigin( ShapePos() );
area.Inflate( dx, dy );
break;
@@ -251,6 +254,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
y = std::min( quadrant1.y, std::min( quadrant2.y, std::min( quadrant3.y, quadrant4.y) ) );
dx = std::max( quadrant1.x, std::max( quadrant2.x, std::max( quadrant3.x, quadrant4.x) ) );
dy = std::max( quadrant1.y, std::max( quadrant2.y, std::max( quadrant3.y, quadrant4.y) ) );
+
area.SetOrigin( m_Pos.x+x, m_Pos.y+y );
area.SetSize( dx-x, dy-y );
break;
@@ -782,18 +786,28 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
arect.Normalize();
arect.Inflate( aAccuracy );
- if( !arect.Intersects( GetBoundingBox() ) )
- return false;
+ EDA_RECT shapeRect;
- if( aContained )
- return arect.Contains( GetBoundingBox() );
+ shapeRect.SetOrigin( ShapePos() );
+ shapeRect.Inflate( GetSize().x / 2, GetSize().y / 2 );
+
+ EDA_RECT bb = GetBoundingBox();
+
+ if( !arect.Intersects( bb ) )
+ return false;
+
+ int dist;
+
+ // This covers total containment for all test cases
+ if( arect.Contains( bb ) )
+ return true;
switch( GetShape() )
{
case PAD_SHAPE_CIRCLE:
return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
case PAD_SHAPE_RECT:
- break;
+ return arect.Intersects( shapeRect, m_Orient );
case PAD_SHAPE_OVAL:
break;
case PAD_SHAPE_TRAPEZOID:
--
2.7.4
From 3cdd41b9de5f12b29ac203621f6b3aa5d466d52d Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Mon, 24 Apr 2017 21:54:53 +1000
Subject: [PATCH 06/12] HitTest for Oval pads
HitTest for Oval pads
Required fix for GetBoundingBox method for Oval Pad shape
---
pcbnew/class_pad.cpp | 137 +++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 116 insertions(+), 21 deletions(-)
diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp
index 64d42c4..958e969 100644
--- a/pcbnew/class_pad.cpp
+++ b/pcbnew/class_pad.cpp
@@ -185,33 +185,79 @@ const EDA_RECT D_PAD::GetBoundingBox() const
{
EDA_RECT area;
wxPoint quadrant1, quadrant2, quadrant3, quadrant4;
- int x, y, dx, dy;
+ int x, y, r, dx, dy;
+
+ wxPoint center = ShapePos();
+ wxPoint endPoint;
+
+ EDA_RECT endRect;
switch( GetShape() )
{
case PAD_SHAPE_CIRCLE:
- area.SetOrigin( m_Pos );
+ area.SetOrigin( center );
area.Inflate( m_Size.x / 2 );
break;
case PAD_SHAPE_OVAL:
- // Calculate the position of each rounded end
- quadrant1.x = m_Size.x/2;
- quadrant1.y = 0;
- quadrant2.x = 0;
- quadrant2.y = m_Size.y/2;
+ /* To get the BoundingBox of an oval pad:
+ * a) If the pad is ROUND, see method for PAD_SHAPE_CIRCLE above
+ * OTHERWISE:
+ * b) Construct EDA_RECT for portion between circular ends
+ * c) Rotate that EDA_RECT
+ * d) Add the circular ends to the EDA_RECT
+ */
+
+ // Test if the shape is circular
+ if( m_Size.x == m_Size.y )
+ {
+ area.SetOrigin( center );
+ area.Inflate( m_Size.x / 2 );
+ break;
+ }
- RotatePoint( &quadrant1, m_Orient );
- RotatePoint( &quadrant2, m_Orient );
+ if( m_Size.x > m_Size.y )
+ {
+ // Pad is horizontal
+ dx = ( m_Size.x - m_Size.y ) / 2;
+ dy = m_Size.y / 2;
+
+ // Location of end-points
+ x = dx;
+ y = 0;
+ r = dy;
+ }
+ else
+ {
+ // Pad is vertical
+ dx = m_Size.x / 2;
+ dy = ( m_Size.y - m_Size.x ) / 2;
- // Calculate the max position of each end, relative to the pad position
- // (the min position is symetrical)
- dx = std::max( std::abs( quadrant1.x ) , std::abs( quadrant2.x ) );
- dy = std::max( std::abs( quadrant1.y ) , std::abs( quadrant2.y ) );
+ x = 0;
+ y = dy;
+ r = dx;
+ }
- // Set the bbox
- area.SetOrigin( ShapePos() );
+ // Construct the center rectangle and rotate
+ area.SetOrigin( center );
area.Inflate( dx, dy );
+ area = area.GetBoundingBoxRotated( center, m_Orient );
+
+ endPoint = wxPoint( x, y );
+ RotatePoint( &endPoint, m_Orient );
+
+ // Add points at each quadrant of circular regions
+ endRect.SetOrigin( center + endPoint );
+ endRect.Inflate( r );
+
+ area.Merge( endRect );
+
+ endRect.SetSize( 0, 0 );
+ endRect.SetOrigin( center - endPoint );
+ endRect.Inflate( r );
+
+ area.Merge( endRect );
+
break;
case PAD_SHAPE_RECT:
@@ -786,17 +832,17 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
arect.Normalize();
arect.Inflate( aAccuracy );
- EDA_RECT shapeRect;
+ wxPoint shapePos = ShapePos();
- shapeRect.SetOrigin( ShapePos() );
- shapeRect.Inflate( GetSize().x / 2, GetSize().y / 2 );
+ EDA_RECT shapeRect;
EDA_RECT bb = GetBoundingBox();
- if( !arect.Intersects( bb ) )
- return false;
+ wxPoint endCenter;
+ int radius;
- int dist;
+ if( !arect.Intersects( bb ) )
+ return false;
// This covers total containment for all test cases
if( arect.Contains( bb ) )
@@ -807,8 +853,57 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
case PAD_SHAPE_CIRCLE:
return arect.IntersectsCircle( GetPosition(), GetBoundingRadius() );
case PAD_SHAPE_RECT:
+ shapeRect.SetOrigin( shapePos );
+ shapeRect.Inflate( m_Size.x / 2, m_Size.y / 2 );
return arect.Intersects( shapeRect, m_Orient );
case PAD_SHAPE_OVAL:
+
+ // Circlular test if dimensions are equal
+ if( m_Size.x == m_Size.y )
+ return arect.IntersectsCircle( shapePos, GetBoundingRadius() );
+
+ shapeRect.SetOrigin( shapePos );
+
+ // Horizontal dimension is greater
+ if( m_Size.x > m_Size.y )
+ {
+ radius = m_Size.y / 2;
+
+ shapeRect.Inflate( m_Size.x / 2 - radius, radius );
+
+ endCenter = wxPoint( m_Size.x / 2 - radius, 0 );
+ RotatePoint( &endCenter, m_Orient );
+
+ // Test circular ends
+ if( arect.IntersectsCircle( shapePos + endCenter, radius ) ||
+ arect.IntersectsCircle( shapePos - endCenter, radius ) )
+ {
+ return true;
+ }
+ }
+ else
+ {
+ radius = m_Size.x / 2;
+
+ shapeRect.Inflate( radius, m_Size.y / 2 - radius );
+
+ endCenter = wxPoint( 0, m_Size.y / 2 - radius );
+ RotatePoint( &endCenter, m_Orient );
+
+ // Test circular ends
+ if( arect.IntersectsCircle( shapePos + endCenter, radius ) ||
+ arect.IntersectsCircle( shapePos - endCenter, radius ) )
+ {
+ return true;
+ }
+ }
+
+ // Test rectangular portion between rounded ends
+ if( arect.Intersects( shapeRect, m_Orient ) )
+ {
+ return true;
+ }
+
break;
case PAD_SHAPE_TRAPEZOID:
break;
--
2.7.4
From 428f0f4a2c5a62f0c3dc5ccec7c2ba517daf55da Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Mon, 24 Apr 2017 22:54:44 +1000
Subject: [PATCH 07/12] HitTest for RoundRect pad
---
pcbnew/class_pad.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 1 deletion(-)
diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp
index 958e969..096d22f 100644
--- a/pcbnew/class_pad.cpp
+++ b/pcbnew/class_pad.cpp
@@ -749,7 +749,7 @@ void D_PAD::GetOblongDrillGeometry( wxPoint& aStartPoint,
bool D_PAD::HitTest( const wxPoint& aPosition ) const
{
- int dx, dy;
+ int dx, dy;
wxPoint shape_pos = ShapePos();
@@ -826,6 +826,9 @@ bool D_PAD::HitTest( const wxPoint& aPosition ) const
return false;
}
+/**
+ * Test if an x,y axis-aligned rectangle hits this pad
+ */
bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
EDA_RECT arect = aRect;
@@ -836,6 +839,8 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
EDA_RECT shapeRect;
+ int r;
+
EDA_RECT bb = GetBoundingBox();
wxPoint endCenter;
@@ -908,6 +913,59 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
case PAD_SHAPE_TRAPEZOID:
break;
case PAD_SHAPE_ROUNDRECT:
+ /* RoundRect intersection can be broken up into simple tests:
+ * a) Test intersection of horizontal rect
+ * b) Test intersection of vertical rect
+ * c) Test intersection of each corner
+ */
+
+
+ r = GetRoundRectCornerRadius();
+
+ /* Test A - intersection of horizontal rect */
+ shapeRect.SetSize( 0, 0 );
+ shapeRect.SetOrigin( shapePos );
+ shapeRect.Inflate( m_Size.x / 2, m_Size.y / 2 - r );
+
+ // Short-circuit test for zero width or height
+ if( shapeRect.GetWidth() > 0 && shapeRect.GetHeight() > 0 &&
+ arect.Intersects( shapeRect, m_Orient ) )
+ {
+ return true;
+ }
+
+ /* Test B - intersection of vertical rect */
+ shapeRect.SetSize( 0, 0 );
+ shapeRect.SetOrigin( shapePos );
+ shapeRect.Inflate( m_Size.x / 2 - r, m_Size.y / 2 );
+
+ // Short-circuit test for zero width or height
+ if( shapeRect.GetWidth() > 0 && shapeRect.GetHeight() > 0 &&
+ arect.Intersects( shapeRect, m_Orient ) )
+ {
+ return true;
+ }
+
+ /* Test C - intersection of each corner */
+
+ endCenter = wxPoint( m_Size.x / 2 - r, m_Size.y / 2 - r );
+ RotatePoint( &endCenter, m_Orient );
+
+ if( arect.IntersectsCircle( shapePos + endCenter, r ) ||
+ arect.IntersectsCircle( shapePos - endCenter, r ) )
+ {
+ return true;
+ }
+
+ endCenter = wxPoint( m_Size.x / 2 - r, -m_Size.y / 2 + r );
+ RotatePoint( &endCenter, m_Orient );
+
+ if( arect.IntersectsCircle( shapePos + endCenter, r ) ||
+ arect.IntersectsCircle( shapePos - endCenter, r ) )
+ {
+ return true;
+ }
+
break;
default:
break;
--
2.7.4
From f6cd8ef81450ce1572982275197f3ecae3572751 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Wed, 26 Apr 2017 19:05:44 +1000
Subject: [PATCH 08/12] HitTest for trapezoid pad
---
pcbnew/class_pad.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 3 deletions(-)
diff --git a/pcbnew/class_pad.cpp b/pcbnew/class_pad.cpp
index 096d22f..300e642 100644
--- a/pcbnew/class_pad.cpp
+++ b/pcbnew/class_pad.cpp
@@ -280,14 +280,18 @@ const EDA_RECT D_PAD::GetBoundingBox() const
break;
case PAD_SHAPE_TRAPEZOID:
- //Use the four corners and track their rotation
+ // Use the four corners and track their rotation
// (Trapezoids will not be symmetric)
+
quadrant1.x = (m_Size.x + m_DeltaSize.y)/2;
quadrant1.y = (m_Size.y - m_DeltaSize.x)/2;
+
quadrant2.x = -(m_Size.x + m_DeltaSize.y)/2;
quadrant2.y = (m_Size.y + m_DeltaSize.x)/2;
+
quadrant3.x = -(m_Size.x - m_DeltaSize.y)/2;
quadrant3.y = -(m_Size.y + m_DeltaSize.x)/2;
+
quadrant4.x = (m_Size.x - m_DeltaSize.y)/2;
quadrant4.y = -(m_Size.y - m_DeltaSize.x)/2;
@@ -301,7 +305,7 @@ const EDA_RECT D_PAD::GetBoundingBox() const
dx = std::max( quadrant1.x, std::max( quadrant2.x, std::max( quadrant3.x, quadrant4.x) ) );
dy = std::max( quadrant1.y, std::max( quadrant2.y, std::max( quadrant3.y, quadrant4.y) ) );
- area.SetOrigin( m_Pos.x+x, m_Pos.y+y );
+ area.SetOrigin( ShapePos().x + x, ShapePos().y + y );
area.SetSize( dx-x, dy-y );
break;
@@ -777,6 +781,7 @@ bool D_PAD::HitTest( const wxPoint& aPosition ) const
wxPoint poly[4];
BuildPadPolygon( poly, wxSize(0,0), 0 );
RotatePoint( &delta, -m_Orient );
+
return TestPointInsidePolygon( poly, 4, delta );
}
@@ -911,7 +916,50 @@ bool D_PAD::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) con
break;
case PAD_SHAPE_TRAPEZOID:
- break;
+ /* Trapezoid intersection tests:
+ * A) Any points of rect inside trapezoid
+ * B) Any points of trapezoid inside rect
+ * C) Any sides of trapezoid cross rect
+ */
+ {
+
+ wxPoint poly[4];
+ BuildPadPolygon( poly, wxSize( 0, 0 ), 0 );
+
+ wxPoint corners[4];
+
+ corners[0] = wxPoint( arect.GetLeft(), arect.GetTop() );
+ corners[1] = wxPoint( arect.GetRight(), arect.GetTop() );
+ corners[2] = wxPoint( arect.GetRight(), arect.GetBottom() );
+ corners[3] = wxPoint( arect.GetLeft(), arect.GetBottom() );
+
+ for( int i=0; i<4; i++ )
+ {
+ RotatePoint( &poly[i], m_Orient );
+ poly[i] += shapePos;
+ }
+
+ for( int ii=0; ii<4; ii++ )
+ {
+ if( TestPointInsidePolygon( poly, 4, corners[ii] ) )
+ {
+ return true;
+ }
+
+ if( arect.Contains( poly[ii] ) )
+ {
+ return true;
+ }
+
+ if( arect.Intersects( poly[ii], poly[(ii+1) % 4] ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+
+ }
case PAD_SHAPE_ROUNDRECT:
/* RoundRect intersection can be broken up into simple tests:
* a) Test intersection of horizontal rect
--
2.7.4
From cb1b21a9e33f9bf85ff2131a0cd05d5fc8c118c4 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Wed, 26 Apr 2017 22:38:41 +1000
Subject: [PATCH 09/12] Updated HitTest for PCB_TEXT and TEXT_MOD
---
pcbnew/class_pcb_text.h | 4 ++--
pcbnew/class_text_mod.cpp | 19 -------------------
pcbnew/class_text_mod.h | 10 +++++++++-
3 files changed, 11 insertions(+), 22 deletions(-)
diff --git a/pcbnew/class_pcb_text.h b/pcbnew/class_pcb_text.h
index 3a2e0e5..ae54a6a 100644
--- a/pcbnew/class_pcb_text.h
+++ b/pcbnew/class_pcb_text.h
@@ -81,7 +81,7 @@ public:
void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) override;
- bool HitTest( const wxPoint& aPosition ) const override
+ virtual bool HitTest( const wxPoint& aPosition ) const override
{
return TextHitTest( aPosition );
}
@@ -89,7 +89,7 @@ public:
/** @copydoc BOARD_ITEM::HitTest(const EDA_RECT& aRect,
* bool aContained = true, int aAccuracy ) const
*/
- bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override
+ virtual bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override
{
return TextHitTest( aRect, aContained, aAccuracy );
}
diff --git a/pcbnew/class_text_mod.cpp b/pcbnew/class_text_mod.cpp
index 0e6bbb7..8aec446 100644
--- a/pcbnew/class_text_mod.cpp
+++ b/pcbnew/class_text_mod.cpp
@@ -181,25 +181,6 @@ void TEXTE_MODULE::SetLocalCoord()
}
}
-
-bool TEXTE_MODULE::HitTest( const wxPoint& aPosition ) const
-{
- wxPoint rel_pos;
- EDA_RECT area = GetTextBox( -1, -1 );
-
- /* Rotate refPos to - angle to test if refPos is within area (which
- * is relative to an horizontal text)
- */
- rel_pos = aPosition;
- RotatePoint( &rel_pos, GetTextPos(), -GetDrawRotation() );
-
- if( area.Contains( rel_pos ) )
- return true;
-
- return false;
-}
-
-
const EDA_RECT TEXTE_MODULE::GetBoundingBox() const
{
double angle = GetDrawRotation();
diff --git a/pcbnew/class_text_mod.h b/pcbnew/class_text_mod.h
index df07ac8..9c4c9ae 100644
--- a/pcbnew/class_text_mod.h
+++ b/pcbnew/class_text_mod.h
@@ -184,7 +184,15 @@ public:
void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) override;
- bool HitTest( const wxPoint& aPosition ) const override;
+ virtual bool HitTest( const wxPoint& aPosition ) const override
+ {
+ return TextHitTest( aPosition );
+ }
+
+ virtual bool HitTest( const EDA_RECT& aRect, bool aContained = false, int aAccuracy = 0 ) const override
+ {
+ return TextHitTest( aRect, aContained, aAccuracy );
+ }
wxString GetClass() const override
{
--
2.7.4
From 81202eefe9330817e8e0e0cf6b1ac60b3720cfcc Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Mon, 1 May 2017 22:10:24 +1000
Subject: [PATCH 10/12] Fixed HitTest for ZONE_CONTAINER
---
pcbnew/class_zone.cpp | 55 ++++++++++++++++++++++++++++++---------------------
1 file changed, 32 insertions(+), 23 deletions(-)
diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index ccaa1db..48aa445 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -539,53 +539,62 @@ bool ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos ) const
bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) const
{
- // Convert to BOX2I
- BOX2I aBox = aRect;
- aBox.Inflate( aAccuracy );
- BOX2I bbox = m_Poly->BBox();
+ // Calculate bounding box for zone
+ EDA_RECT bbox = GetBoundingBox();
bbox.Normalize();
+ EDA_RECT arect = aRect;
+ arect.Normalize();
+ arect.Inflate( aAccuracy );
+
if( aContained )
- return aBox.Contains( bbox );
+ {
+ return arect.Contains( bbox );
+ }
else // Test for intersection between aBox and the polygon
// For a polygon, using its bounding box has no sense here
{
// Fast test: if aBox is outside the polygon bounding box,
// rectangles cannot intersect
- if( ! bbox.Intersects( aBox ) )
+ if( !arect.Intersects( bbox ) )
return false;
// aBox is inside the polygon bounding box,
// and can intersect the polygon: use a fine test.
// aBox intersects the polygon if at least one aBox corner
// is inside the polygon
- wxPoint corner = static_cast<wxPoint>( aBox.GetOrigin() );
-
- if( HitTestInsideZone( corner ) )
- return true;
-
- corner.x = aBox.GetEnd().x;
-
- if( HitTestInsideZone( corner ) )
- return true;
-
- corner = static_cast<wxPoint>( aBox.GetEnd() );
-
- if( HitTestInsideZone( corner ) )
- return true;
+ wxPoint origin = arect.GetOrigin();
- corner.x = aBox.GetOrigin().x;
+ int w = arect.GetWidth();
+ int h = arect.GetHeight();
- if( HitTestInsideZone( corner ) )
+ if ( HitTestInsideZone( origin ) ||
+ HitTestInsideZone( origin + wxPoint( w, 0 ) ) ||
+ HitTestInsideZone( origin + wxPoint( w, h ) ) ||
+ HitTestInsideZone( origin + wxPoint( 0, h ) ) )
+ {
return true;
+ }
// No corner inside aBox, but outlines can intersect aBox
// if one of outline corners is inside aBox
int count = m_Poly->TotalVertices();
for( int ii =0; ii < count; ii++ )
{
- if( aBox.Contains( m_Poly->Vertex( ii ) ) )
+ auto vertex = m_Poly->Vertex( ii );
+ auto vertexNext = m_Poly->Vertex( ( ii + 1 ) % count );
+
+ // Test if the point is within the rect
+ if( arect.Contains( ( wxPoint ) vertex ) )
+ {
return true;
+ }
+
+ // Test if this edge intersects the rect
+ if( arect.Intersects( ( wxPoint ) vertex, ( wxPoint ) vertexNext ) )
+ {
+ return true;
+ }
}
return false;
--
2.7.4
From a19355b9e87ed81de3e66297719bb52758da2208 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 2 May 2017 16:44:41 +1000
Subject: [PATCH 11/12] Fixed HitTest for text and modules
---
include/eda_text.h | 4 ++--
pcbnew/class_module.cpp | 22 +++++++++++++++++++++-
pcbnew/class_text_mod.cpp | 29 +++++++++++++++++++++++++++++
pcbnew/class_text_mod.h | 4 ++++
4 files changed, 56 insertions(+), 3 deletions(-)
diff --git a/include/eda_text.h b/include/eda_text.h
index a20aacc..e0bbf59 100644
--- a/include/eda_text.h
+++ b/include/eda_text.h
@@ -260,7 +260,7 @@ public:
* @param aAccuracy - Amount to inflate the bounding box.
* @return bool - true if a hit, else false
*/
- bool TextHitTest( const wxPoint& aPoint, int aAccuracy = 0 ) const;
+ virtual bool TextHitTest( const wxPoint& aPoint, int aAccuracy = 0 ) const;
/**
* Function TextHitTest (overloaded)
@@ -271,7 +271,7 @@ public:
* @param aAccuracy - Amount to inflate the bounding box.
* @return bool - true if a hit, else false
*/
- bool TextHitTest( const EDA_RECT& aRect, bool aContains = false, int aAccuracy = 0 ) const;
+ virtual bool TextHitTest( const EDA_RECT& aRect, bool aContains = false, int aAccuracy = 0 ) const;
/**
* Function LenSize
diff --git a/pcbnew/class_module.cpp b/pcbnew/class_module.cpp
index ecfcd9a..b79ae81 100644
--- a/pcbnew/class_module.cpp
+++ b/pcbnew/class_module.cpp
@@ -614,7 +614,27 @@ bool MODULE::HitTest( const EDA_RECT& aRect, bool aContained, int aAccuracy ) co
if( aContained )
return arect.Contains( m_BoundaryBox );
else
- return m_BoundaryBox.Intersects( arect );
+ {
+ // If the rect does not intersect the bounding box, skip any tests
+ if( !aRect.Intersects( GetBoundingBox() ) )
+ return false;
+
+ // Determine if any elements in the MODULE intersect the rect
+ for( D_PAD* pad = m_Pads; pad; pad = pad->Next() )
+ {
+ if( pad->HitTest( arect, false, 0 ) )
+ return true;
+ }
+
+ for( BOARD_ITEM* item = m_Drawings; item; item = item->Next() )
+ {
+ if( item->HitTest( arect, false, 0 ) )
+ return true;
+ }
+
+ // No items were hit
+ return false;
+ }
}
diff --git a/pcbnew/class_text_mod.cpp b/pcbnew/class_text_mod.cpp
index 8aec446..9d807b5 100644
--- a/pcbnew/class_text_mod.cpp
+++ b/pcbnew/class_text_mod.cpp
@@ -89,6 +89,35 @@ void TEXTE_MODULE::SetTextAngle( double aAngle )
EDA_TEXT::SetTextAngle( NormalizeAngle360( aAngle ) );
}
+bool TEXTE_MODULE::TextHitTest( const wxPoint& aPoint, int aAccuracy ) const
+{
+ EDA_RECT rect = GetTextBox( -1 );
+ wxPoint location = aPoint;
+
+ rect.Inflate( aAccuracy );
+
+ RotatePoint( &location, GetTextPos(), -GetDrawRotation() );
+
+ return rect.Contains( location );
+}
+
+bool TEXTE_MODULE::TextHitTest( const EDA_RECT& aRect, bool aContains, int aAccuracy ) const
+{
+ EDA_RECT rect = aRect;
+
+ rect.Inflate( aAccuracy );
+
+ if( aContains )
+ {
+ return rect.Contains( GetBoundingBox() );
+ }
+ else
+ {
+ return rect.Intersects( GetTextBox( -1 ), GetDrawRotation() );
+ }
+
+}
+
void TEXTE_MODULE::Rotate( const wxPoint& aRotCentre, double aAngle )
{
diff --git a/pcbnew/class_text_mod.h b/pcbnew/class_text_mod.h
index 9c4c9ae..80d24b7 100644
--- a/pcbnew/class_text_mod.h
+++ b/pcbnew/class_text_mod.h
@@ -184,6 +184,10 @@ public:
void GetMsgPanelInfo( std::vector< MSG_PANEL_ITEM >& aList ) override;
+ virtual bool TextHitTest( const wxPoint& aPoint, int aAccuracy = 0 ) const override;
+
+ virtual bool TextHitTest( const EDA_RECT& aRect, bool aContains = false, int aAccuracy = 0 ) const override;
+
virtual bool HitTest( const wxPoint& aPosition ) const override
{
return TextHitTest( aPosition );
--
2.7.4
From ad33940b358b4aaf07e98b2e2101d5eb3b184c9c Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 2 May 2017 17:14:07 +1000
Subject: [PATCH 12/12] Adjusted selection for ZONE
---
pcbnew/class_zone.cpp | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/pcbnew/class_zone.cpp b/pcbnew/class_zone.cpp
index 48aa445..0c4f4e3 100644
--- a/pcbnew/class_zone.cpp
+++ b/pcbnew/class_zone.cpp
@@ -563,11 +563,14 @@ bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccur
// and can intersect the polygon: use a fine test.
// aBox intersects the polygon if at least one aBox corner
// is inside the polygon
+
+ /*
wxPoint origin = arect.GetOrigin();
int w = arect.GetWidth();
int h = arect.GetHeight();
+
if ( HitTestInsideZone( origin ) ||
HitTestInsideZone( origin + wxPoint( w, 0 ) ) ||
HitTestInsideZone( origin + wxPoint( w, h ) ) ||
@@ -575,6 +578,7 @@ bool ZONE_CONTAINER::HitTest( const EDA_RECT& aRect, bool aContained, int aAccur
{
return true;
}
+ */
// No corner inside aBox, but outlines can intersect aBox
// if one of outline corners is inside aBox
--
2.7.4
Follow ups