Merged Tom's branch
This commit is contained in:
commit
82fe1a4972
|
@ -163,6 +163,10 @@ set(COMMON_SRCS
|
||||||
tool/tool_event.cpp
|
tool/tool_event.cpp
|
||||||
tool/tool_interactive.cpp
|
tool/tool_interactive.cpp
|
||||||
tool/context_menu.cpp
|
tool/context_menu.cpp
|
||||||
|
|
||||||
|
geometry/seg.cpp
|
||||||
|
geometry/shape_line_chain.cpp
|
||||||
|
geometry/shape_collisions.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(common STATIC ${COMMON_SRCS})
|
add_library(common STATIC ${COMMON_SRCS})
|
||||||
|
|
|
@ -87,8 +87,15 @@ EDA_DRAW_PANEL_GAL::EDA_DRAW_PANEL_GAL( wxWindow* aParentWindow, wxWindowID aWin
|
||||||
Connect( wxEVT_MIDDLE_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_MIDDLE_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_MIDDLE_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_MIDDLE_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_MOUSEWHEEL, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
|
// Connect( wxEVT_CHAR_HOOK, wxEventHandler( EDA_DRAW_PANEL_GAL::skipEvent ) );
|
||||||
Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_KEY_UP, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
Connect( wxEVT_KEY_DOWN, wxEventHandler( EDA_DRAW_PANEL_GAL::onEvent ), NULL, this );
|
||||||
|
// Connect( wxEVT_ENTER_WINDOW, wxEventHandler( EDA_DRAW_PANEL_GAL::onEnter ), NULL, this );
|
||||||
|
|
||||||
|
m_refreshTimer.SetOwner( this );
|
||||||
|
Connect( wxEVT_TIMER, wxTimerEventHandler( EDA_DRAW_PANEL_GAL::onRefreshTimer ), NULL, this );
|
||||||
|
|
||||||
|
this->SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -110,6 +117,9 @@ EDA_DRAW_PANEL_GAL::~EDA_DRAW_PANEL_GAL()
|
||||||
|
|
||||||
void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
|
void EDA_DRAW_PANEL_GAL::onPaint( wxPaintEvent& WXUNUSED( aEvent ) )
|
||||||
{
|
{
|
||||||
|
m_pendingRefresh = false;
|
||||||
|
m_lastRefresh = wxGetLocalTimeMillis();
|
||||||
|
|
||||||
#ifdef __WXDEBUG__
|
#ifdef __WXDEBUG__
|
||||||
prof_counter time;
|
prof_counter time;
|
||||||
prof_start( &time, false );
|
prof_start( &time, false );
|
||||||
|
@ -144,13 +154,36 @@ void EDA_DRAW_PANEL_GAL::onSize( wxSizeEvent& aEvent )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect )
|
void EDA_DRAW_PANEL_GAL::onRefreshTimer( wxTimerEvent& aEvent )
|
||||||
{
|
{
|
||||||
wxPaintEvent redrawEvent;
|
wxPaintEvent redrawEvent;
|
||||||
wxPostEvent( this, redrawEvent );
|
wxPostEvent( this, redrawEvent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EDA_DRAW_PANEL_GAL::Refresh( bool eraseBackground, const wxRect* rect )
|
||||||
|
{
|
||||||
|
if( m_pendingRefresh )
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxLongLong t = wxGetLocalTimeMillis();
|
||||||
|
wxLongLong delta = t - m_lastRefresh;
|
||||||
|
|
||||||
|
if( delta >= MinRefreshPeriod )
|
||||||
|
{
|
||||||
|
wxPaintEvent redrawEvent;
|
||||||
|
wxPostEvent( this, redrawEvent );
|
||||||
|
m_pendingRefresh = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// One shot timer
|
||||||
|
m_refreshTimer.Start( ( MinRefreshPeriod - delta ).ToLong(), true );
|
||||||
|
m_pendingRefresh = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
|
void EDA_DRAW_PANEL_GAL::SwitchBackend( GalType aGalType )
|
||||||
{
|
{
|
||||||
// Do not do anything if the currently used GAL is correct
|
// Do not do anything if the currently used GAL is correct
|
||||||
|
@ -205,5 +238,19 @@ void EDA_DRAW_PANEL_GAL::onEvent( wxEvent& aEvent )
|
||||||
m_eventDispatcher->DispatchWxEvent( aEvent );
|
m_eventDispatcher->DispatchWxEvent( aEvent );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if( m_view->IsDirty() )
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EDA_DRAW_PANEL_GAL::onEnter ( wxEvent& aEvent )
|
||||||
|
{
|
||||||
|
SetFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void EDA_DRAW_PANEL_GAL::skipEvent( wxEvent& aEvent )
|
||||||
|
{
|
||||||
|
// This is necessary for CHAR_HOOK event to generate KEY_UP and KEY_DOWN events
|
||||||
|
aEvent.Skip();
|
||||||
|
}
|
||||||
|
|
|
@ -58,3 +58,117 @@ const bool COLOR4D::operator!=( const COLOR4D& aColor )
|
||||||
{
|
{
|
||||||
return a != aColor.a || r != aColor.r || g != aColor.g || b != aColor.b;
|
return a != aColor.a || r != aColor.r || g != aColor.g || b != aColor.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void COLOR4D::ToHSV( double& aOutH, double& aOutS, double& aOutV ) const
|
||||||
|
{
|
||||||
|
double min, max, delta;
|
||||||
|
|
||||||
|
min = r < g ? r : g;
|
||||||
|
min = min < b ? min : b;
|
||||||
|
|
||||||
|
max = r > g ? r : g;
|
||||||
|
max = max > b ? max : b;
|
||||||
|
|
||||||
|
aOutV = max; // v
|
||||||
|
delta = max - min;
|
||||||
|
|
||||||
|
if( max > 0.0 )
|
||||||
|
{
|
||||||
|
aOutS = ( delta / max ); // s
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// r = g = b = 0 // s = 0, v is undefined
|
||||||
|
aOutS = 0.0;
|
||||||
|
aOutH = NAN; // its now undefined
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( r >= max ) // > is bogus, just keeps compiler happy
|
||||||
|
aOutH = ( g - b ) / delta; // between yellow & magenta
|
||||||
|
else if( g >= max )
|
||||||
|
aOutH = 2.0 + ( b - r ) / delta; // between cyan & yellow
|
||||||
|
else
|
||||||
|
aOutH = 4.0 + ( r - g ) / delta; // between magenta & cyan
|
||||||
|
|
||||||
|
aOutH *= 60.0; // degrees
|
||||||
|
|
||||||
|
if( aOutH < 0.0 )
|
||||||
|
aOutH += 360.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void COLOR4D::FromHSV( double aInH, double aInS, double aInV )
|
||||||
|
{
|
||||||
|
double hh, p, q, t, ff;
|
||||||
|
long i;
|
||||||
|
|
||||||
|
if( aInS <= 0.0 ) // < is bogus, just shuts up warnings
|
||||||
|
{
|
||||||
|
r = aInV;
|
||||||
|
g = aInV;
|
||||||
|
b = aInV;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hh = aInH;
|
||||||
|
if( hh >= 360.0 )
|
||||||
|
hh = 0.0;
|
||||||
|
hh /= 60.0;
|
||||||
|
|
||||||
|
i = (long) hh;
|
||||||
|
ff = hh - i;
|
||||||
|
|
||||||
|
p = aInV * ( 1.0 - aInS );
|
||||||
|
q = aInV * ( 1.0 - ( aInS * ff ) );
|
||||||
|
t = aInV * ( 1.0 - ( aInS * ( 1.0 - ff ) ) );
|
||||||
|
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
r = aInV;
|
||||||
|
g = t;
|
||||||
|
b = p;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r = q;
|
||||||
|
g = aInV;
|
||||||
|
b = p;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
r = p;
|
||||||
|
g = aInV;
|
||||||
|
b = t;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
r = p;
|
||||||
|
g = q;
|
||||||
|
b = aInV;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
r = t;
|
||||||
|
g = p;
|
||||||
|
b = aInV;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
default:
|
||||||
|
r = aInV;
|
||||||
|
g = p;
|
||||||
|
b = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
COLOR4D& COLOR4D::Saturate( double aFactor )
|
||||||
|
{
|
||||||
|
double h, s, v;
|
||||||
|
ToHSV( h, s, v );
|
||||||
|
FromHSV( h, aFactor, 1.0 );
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <geometry/seg.h>
|
||||||
|
|
||||||
|
template <typename T> int sgn(T val) {
|
||||||
|
return (T(0) < val) - (val < T(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEG::PointCloserThan (const VECTOR2I& aP, int dist) const
|
||||||
|
{
|
||||||
|
VECTOR2I d = b - a;
|
||||||
|
ecoord dist_sq = (ecoord) dist * dist;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
VECTOR2I nearest;
|
||||||
|
nearest.x = a.x + rescale(t, (ecoord)d.x, l_squared);
|
||||||
|
nearest.y = a.y + rescale(t, (ecoord)d.y, l_squared);
|
||||||
|
|
||||||
|
return (nearest - aP).SquaredEuclideanNorm() <= dist_sq;
|
||||||
|
}
|
||||||
|
|
||||||
|
SEG::ecoord SEG::SquaredDistance( const SEG& aSeg ) const
|
||||||
|
{
|
||||||
|
// fixme: rather inefficient....
|
||||||
|
if(Intersect(aSeg))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
const VECTOR2I pts[4] =
|
||||||
|
{
|
||||||
|
aSeg.NearestPoint(a) - a,
|
||||||
|
aSeg.NearestPoint(b) - b,
|
||||||
|
NearestPoint(aSeg.a) - aSeg.a,
|
||||||
|
NearestPoint(aSeg.b) - aSeg.b
|
||||||
|
};
|
||||||
|
|
||||||
|
ecoord m = VECTOR2I::ECOORD_MAX;
|
||||||
|
for (int i = 0; i<4 ; i++)
|
||||||
|
m = std::min(m, pts[i].SquaredEuclideanNorm());
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
#undef CHK
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SEG::Contains(const VECTOR2I& aP) const
|
||||||
|
{
|
||||||
|
return PointCloserThan(aP, 1);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math/vector2d.h>
|
||||||
|
|
||||||
|
#include <geometry/shape.h>
|
||||||
|
#include <geometry/shape_line_chain.h>
|
||||||
|
#include <geometry/shape_circle.h>
|
||||||
|
#include <geometry/shape_rect.h>
|
||||||
|
|
||||||
|
typedef typename VECTOR2I::extended_type ecoord;
|
||||||
|
|
||||||
|
static inline bool Collide( const SHAPE_CIRCLE& a, const SHAPE_CIRCLE& b, int clearance, bool needMTV, VECTOR2I& aMTV )
|
||||||
|
{
|
||||||
|
ecoord min_dist = clearance + a.GetRadius() + b.GetRadius();
|
||||||
|
ecoord min_dist_sq = min_dist * min_dist;
|
||||||
|
|
||||||
|
const VECTOR2I delta = b.GetCenter() - a.GetCenter();
|
||||||
|
|
||||||
|
ecoord dist_sq = delta.SquaredEuclideanNorm();
|
||||||
|
|
||||||
|
if ( dist_sq >= min_dist_sq )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ( needMTV )
|
||||||
|
aMTV = delta.Resize( sqrt (abs(min_dist_sq - dist_sq)) + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool Collide( const SHAPE_RECT& a, const SHAPE_CIRCLE& b, int clearance, bool needMTV, VECTOR2I& aMTV )
|
||||||
|
{
|
||||||
|
const VECTOR2I c = b.GetCenter();
|
||||||
|
const VECTOR2I p0 = a.GetPosition();
|
||||||
|
const VECTOR2I size = a.GetSize();
|
||||||
|
const ecoord r = b.GetRadius();
|
||||||
|
const ecoord min_dist = clearance + r;
|
||||||
|
const ecoord min_dist_sq = min_dist * min_dist;
|
||||||
|
|
||||||
|
if (a.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(!needMTV)
|
||||||
|
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(!needMTV)
|
||||||
|
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& a, const SHAPE_LINE_CHAIN& b, int clearance, bool needMTV, VECTOR2I& aMTV )
|
||||||
|
{
|
||||||
|
for (int s = 0; s < b.SegmentCount(); s++)
|
||||||
|
{
|
||||||
|
if ( a.Collide (b.CSegment(s), clearance))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool Collide( const SHAPE_LINE_CHAIN& a, const SHAPE_LINE_CHAIN& b, int clearance, bool needMTV, VECTOR2I& aMTV )
|
||||||
|
{
|
||||||
|
for( int i = 0; i < b.SegmentCount() ;i++)
|
||||||
|
if(a.Collide(b.CSegment(i), clearance))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline bool Collide( const SHAPE_RECT& a, const SHAPE_LINE_CHAIN& b, int clearance, bool needMTV, VECTOR2I& aMTV )
|
||||||
|
{
|
||||||
|
for (int s = 0; s < b.SegmentCount(); s++)
|
||||||
|
{
|
||||||
|
SEG seg = b.CSegment(s);
|
||||||
|
if ( a.Collide (seg, clearance))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool CollideShapes ( const SHAPE *a, const SHAPE *b, int clearance, bool needMTV, VECTOR2I& aMTV )
|
||||||
|
{
|
||||||
|
switch(a->Type())
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
switch(b->Type())
|
||||||
|
{
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return Collide( *static_cast<const SHAPE_RECT *> (a), *static_cast<const SHAPE_CIRCLE *> (b), clearance, needMTV, aMTV );
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return Collide( *static_cast<const SHAPE_RECT *> (a), *static_cast<const SHAPE_LINE_CHAIN *> (b), clearance, needMTV, aMTV );
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SH_CIRCLE:
|
||||||
|
switch(b->Type())
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
return Collide( *static_cast<const SHAPE_RECT *> (b), *static_cast<const SHAPE_CIRCLE *> (a), clearance, needMTV, aMTV );
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return Collide( *static_cast<const SHAPE_CIRCLE *> (a), *static_cast<const SHAPE_CIRCLE *> (b), clearance, needMTV, aMTV );
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return Collide( *static_cast<const SHAPE_CIRCLE *> (a), *static_cast<const SHAPE_LINE_CHAIN *> (b), clearance, needMTV, aMTV );
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
switch(b->Type())
|
||||||
|
{
|
||||||
|
case SH_RECT:
|
||||||
|
return Collide( *static_cast<const SHAPE_RECT *> (b), *static_cast<const SHAPE_LINE_CHAIN *> (a), clearance, needMTV, aMTV );
|
||||||
|
case SH_CIRCLE:
|
||||||
|
return Collide( *static_cast<const SHAPE_CIRCLE *> (b), *static_cast<const SHAPE_LINE_CHAIN *> (a), clearance, needMTV, aMTV );
|
||||||
|
case SH_LINE_CHAIN:
|
||||||
|
return Collide( *static_cast<const SHAPE_LINE_CHAIN *> (a), *static_cast<const SHAPE_LINE_CHAIN *> (b), clearance, needMTV, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAPE::Collide ( const SHAPE *aShape, int aClerance ) const
|
||||||
|
{
|
||||||
|
VECTOR2I dummy;
|
||||||
|
return CollideShapes( this, aShape, aClerance, false, dummy);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,465 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <geometry/shape_line_chain.h>
|
||||||
|
#include <geometry/shape_circle.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using boost::optional;
|
||||||
|
|
||||||
|
bool SHAPE_LINE_CHAIN::Collide ( const VECTOR2I& aP, int aClearance ) const
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAPE_LINE_CHAIN::Collide ( const BOX2I& aBox, int aClearance ) const
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SHAPE_LINE_CHAIN::Length() const
|
||||||
|
{
|
||||||
|
int l = 0;
|
||||||
|
for (int i = 0; i < SegmentCount(); i++)
|
||||||
|
l += CSegment(i).Length();
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAPE_LINE_CHAIN::Replace( int start_index, int end_index, const VECTOR2I& aP)
|
||||||
|
{
|
||||||
|
if(end_index < 0)
|
||||||
|
end_index += PointCount();
|
||||||
|
if(start_index < 0)
|
||||||
|
start_index += PointCount();
|
||||||
|
|
||||||
|
if (start_index == end_index)
|
||||||
|
m_points [start_index] = aP;
|
||||||
|
else {
|
||||||
|
m_points.erase (m_points.begin() + start_index + 1, m_points.begin() + end_index + 1);
|
||||||
|
m_points [start_index] = aP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAPE_LINE_CHAIN::Replace( int start_index, int end_index, const SHAPE_LINE_CHAIN& aLine)
|
||||||
|
{
|
||||||
|
if(end_index < 0)
|
||||||
|
end_index += PointCount();
|
||||||
|
if(start_index < 0)
|
||||||
|
start_index += PointCount();
|
||||||
|
|
||||||
|
m_points.erase (m_points.begin() + start_index, m_points.begin() + end_index + 1);
|
||||||
|
m_points.insert (m_points.begin() + start_index, aLine.m_points.begin(), aLine.m_points.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SHAPE_LINE_CHAIN::Remove( int start_index, int end_index)
|
||||||
|
{
|
||||||
|
if(end_index < 0)
|
||||||
|
end_index += PointCount();
|
||||||
|
if(start_index < 0)
|
||||||
|
start_index += PointCount();
|
||||||
|
|
||||||
|
m_points.erase (m_points.begin() + start_index, m_points.begin() + end_index + 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));
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ii >= 0)
|
||||||
|
{
|
||||||
|
m_points.insert(m_points.begin() + ii + 1, aP);
|
||||||
|
return ii + 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;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int start_index, int end_index ) const
|
||||||
|
{
|
||||||
|
SHAPE_LINE_CHAIN rv;
|
||||||
|
|
||||||
|
if(end_index < 0)
|
||||||
|
end_index += PointCount();
|
||||||
|
if(start_index < 0)
|
||||||
|
start_index += PointCount();
|
||||||
|
|
||||||
|
for(int i = start_index; i<= end_index; i++)
|
||||||
|
rv.Append(m_points[i]);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct compareOriginDistance {
|
||||||
|
compareOriginDistance( VECTOR2I& aOrigin ):
|
||||||
|
m_origin(aOrigin) {};
|
||||||
|
|
||||||
|
bool operator()(const SHAPE_LINE_CHAIN::Intersection &a, const SHAPE_LINE_CHAIN::Intersection& b)
|
||||||
|
{
|
||||||
|
return (m_origin - a.p).EuclideanNorm() < (m_origin - b.p).EuclideanNorm();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAPE_LINE_CHAIN::PointInside( const VECTOR2I& aP) const
|
||||||
|
{
|
||||||
|
if(!m_closed || SegmentCount() < 3)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int cur = CSegment(0).Side(aP);
|
||||||
|
if(cur == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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 (s.Side(aP) != cur)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SHAPE_LINE_CHAIN::PointOnEdge( const VECTOR2I& aP) const
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
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>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint(const VECTOR2I& aP) const
|
||||||
|
{
|
||||||
|
int min_d = INT_MAX;
|
||||||
|
int nearest;
|
||||||
|
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;
|
||||||
|
|
||||||
|
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() << " ";
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
|
@ -47,6 +47,7 @@ public:
|
||||||
else if( type == wxEVT_COMMAND_MENU_SELECTED )
|
else if( type == wxEVT_COMMAND_MENU_SELECTED )
|
||||||
evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() );
|
evt = TOOL_EVENT( TC_Command, TA_ContextMenuChoice, aEvent.GetId() );
|
||||||
|
|
||||||
|
if( m_menu->m_tool )
|
||||||
m_menu->m_tool->GetManager()->ProcessEvent( evt );
|
m_menu->m_tool->GetManager()->ProcessEvent( evt );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
#include <tool/tool_manager.h>
|
#include <tool/tool_manager.h>
|
||||||
#include <tool/tool_dispatcher.h>
|
#include <tool/tool_dispatcher.h>
|
||||||
#include <view/view.h>
|
#include <view/view.h>
|
||||||
#include <view/view_controls.h>
|
|
||||||
|
|
||||||
#include <class_drawpanel_gal.h>
|
#include <class_drawpanel_gal.h>
|
||||||
|
|
||||||
|
@ -56,6 +55,8 @@ struct TOOL_DISPATCHER::ButtonState
|
||||||
bool pressed;
|
bool pressed;
|
||||||
|
|
||||||
VECTOR2D dragOrigin;
|
VECTOR2D dragOrigin;
|
||||||
|
VECTOR2D downPosition;
|
||||||
|
|
||||||
double dragMaxDelta;
|
double dragMaxDelta;
|
||||||
|
|
||||||
TOOL_MouseButtons button;
|
TOOL_MouseButtons button;
|
||||||
|
@ -119,11 +120,21 @@ int TOOL_DISPATCHER::decodeModifiers( const wxKeyboardState* aState ) const
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxPoint TOOL_DISPATCHER::getCurrentMousePos() const
|
||||||
|
{
|
||||||
|
wxPoint msp = wxGetMousePosition();
|
||||||
|
wxPoint winp = m_editFrame->GetGalCanvas()->GetScreenPosition();
|
||||||
|
|
||||||
|
return wxPoint( msp.x - winp.x, msp.y - winp.y );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion )
|
bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion )
|
||||||
{
|
{
|
||||||
ButtonState* st = m_buttons[aIndex];
|
ButtonState* st = m_buttons[aIndex];
|
||||||
wxEventType type = aEvent.GetEventType();
|
wxEventType type = aEvent.GetEventType();
|
||||||
optional<TOOL_EVENT> evt;
|
optional<TOOL_EVENT> evt;
|
||||||
|
bool isClick = false;
|
||||||
|
|
||||||
bool up = type == st->upEvent;
|
bool up = type == st->upEvent;
|
||||||
bool down = type == st->downEvent;
|
bool down = type == st->downEvent;
|
||||||
|
@ -135,13 +146,13 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
|
||||||
{
|
{
|
||||||
st->downTimestamp = wxGetLocalTimeMillis();
|
st->downTimestamp = wxGetLocalTimeMillis();
|
||||||
st->dragOrigin = m_lastMousePos;
|
st->dragOrigin = m_lastMousePos;
|
||||||
|
st->downPosition = m_lastMousePos;
|
||||||
st->dragMaxDelta = 0;
|
st->dragMaxDelta = 0;
|
||||||
st->pressed = true;
|
st->pressed = true;
|
||||||
evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args );
|
evt = TOOL_EVENT( TC_Mouse, TA_MouseDown, args );
|
||||||
}
|
}
|
||||||
else if( up )
|
else if( up )
|
||||||
{
|
{
|
||||||
bool isClick = false;
|
|
||||||
st->pressed = false;
|
st->pressed = false;
|
||||||
|
|
||||||
if( st->dragging )
|
if( st->dragging )
|
||||||
|
@ -157,14 +168,9 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
|
||||||
else
|
else
|
||||||
isClick = true;
|
isClick = true;
|
||||||
|
|
||||||
|
|
||||||
if( isClick )
|
if( isClick )
|
||||||
{
|
|
||||||
if( st->triggerContextMenu && !mods )
|
|
||||||
{}
|
|
||||||
// evt = TOOL_EVENT( TC_Command, TA_ContextMenu );
|
|
||||||
else
|
|
||||||
evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args );
|
evt = TOOL_EVENT( TC_Mouse, TA_MouseClick, args );
|
||||||
}
|
|
||||||
|
|
||||||
st->dragging = false;
|
st->dragging = false;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +193,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
|
||||||
|
|
||||||
if( evt )
|
if( evt )
|
||||||
{
|
{
|
||||||
evt->SetMousePosition( m_lastMousePos );
|
evt->SetMousePosition( isClick ? st->downPosition : m_lastMousePos );
|
||||||
m_toolMgr->ProcessEvent( *evt );
|
m_toolMgr->ProcessEvent( *evt );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -200,7 +206,7 @@ bool TOOL_DISPATCHER::handleMouseButton( wxEvent& aEvent, int aIndex, bool aMoti
|
||||||
void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||||
{
|
{
|
||||||
bool motion = false, buttonEvents = false;
|
bool motion = false, buttonEvents = false;
|
||||||
VECTOR2D pos, screenPos;
|
VECTOR2D pos;
|
||||||
optional<TOOL_EVENT> evt;
|
optional<TOOL_EVENT> evt;
|
||||||
|
|
||||||
int type = aEvent.GetEventType();
|
int type = aEvent.GetEventType();
|
||||||
|
@ -211,9 +217,9 @@ void TOOL_DISPATCHER::DispatchWxEvent( wxEvent& aEvent )
|
||||||
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
|
type == wxEVT_MIDDLE_DOWN || type == wxEVT_MIDDLE_UP ||
|
||||||
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP )
|
type == wxEVT_RIGHT_DOWN || type == wxEVT_RIGHT_UP )
|
||||||
{
|
{
|
||||||
screenPos = m_toolMgr->GetViewControls()->GetCursorPosition();
|
wxMouseEvent* me = static_cast<wxMouseEvent*>( &aEvent );
|
||||||
pos = getView()->ToWorld( screenPos );
|
|
||||||
|
|
||||||
|
pos = getView()->ToWorld ( getCurrentMousePos() );
|
||||||
if( pos != m_lastMousePos )
|
if( pos != m_lastMousePos )
|
||||||
{
|
{
|
||||||
motion = true;
|
motion = true;
|
||||||
|
@ -264,6 +270,10 @@ void TOOL_DISPATCHER::DispatchWxCommand( wxCommandEvent& aEvent )
|
||||||
|
|
||||||
switch( aEvent.GetId() )
|
switch( aEvent.GetId() )
|
||||||
{
|
{
|
||||||
|
case ID_PNS_ROUTER_TOOL:
|
||||||
|
toolName = "pcbnew.InteractiveRouter";
|
||||||
|
activateTool = true;
|
||||||
|
break;
|
||||||
case ID_SELECTION_TOOL:
|
case ID_SELECTION_TOOL:
|
||||||
toolName = "pcbnew.InteractiveSelection";
|
toolName = "pcbnew.InteractiveSelection";
|
||||||
activateTool = true;
|
activateTool = true;
|
||||||
|
@ -273,4 +283,3 @@ void TOOL_DISPATCHER::DispatchWxCommand( wxCommandEvent& aEvent )
|
||||||
if( activateTool && m_editFrame->IsGalCanvasActive() )
|
if( activateTool && m_editFrame->IsGalCanvasActive() )
|
||||||
m_toolMgr->InvokeTool( toolName );
|
m_toolMgr->InvokeTool( toolName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,8 +81,10 @@ struct TOOL_MANAGER::TOOL_STATE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TOOL_MANAGER::TOOL_MANAGER()
|
TOOL_MANAGER::TOOL_MANAGER() :
|
||||||
|
m_model( NULL ), m_view( NULL )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,11 +292,17 @@ bool TOOL_MANAGER::ProcessEvent( TOOL_EVENT& aEvent )
|
||||||
{
|
{
|
||||||
TOOL_STATE* st = m_toolIdIndex[toolId];
|
TOOL_STATE* st = m_toolIdIndex[toolId];
|
||||||
|
|
||||||
if( st->contextMenuTrigger == CMENU_NOW )
|
if( st->contextMenuTrigger != CMENU_OFF )
|
||||||
{
|
{
|
||||||
|
if( st->contextMenuTrigger == CMENU_BUTTON && !aEvent.IsClick( MB_Right ) )
|
||||||
|
break;
|
||||||
|
|
||||||
st->pendingWait = true;
|
st->pendingWait = true;
|
||||||
st->waitEvents = TOOL_EVENT( TC_Any, TA_Any );
|
st->waitEvents = TOOL_EVENT( TC_Any, TA_Any );
|
||||||
|
|
||||||
|
if( st->contextMenuTrigger == CMENU_NOW )
|
||||||
st->contextMenuTrigger = CMENU_OFF;
|
st->contextMenuTrigger = CMENU_OFF;
|
||||||
|
|
||||||
GetEditFrame()->PopupMenu( st->contextMenu->GetMenu() );
|
GetEditFrame()->PopupMenu( st->contextMenu->GetMenu() );
|
||||||
|
|
||||||
TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
|
TOOL_EVENT evt( TC_Command, TA_ContextMenuChoice );
|
||||||
|
|
|
@ -71,6 +71,16 @@ void VIEW_GROUP::Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VIEW_GROUP::FreeItems()
|
||||||
|
{
|
||||||
|
BOOST_FOREACH( VIEW_ITEM* item, m_items )
|
||||||
|
{
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
m_items.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned int VIEW_GROUP::GetSize() const
|
unsigned int VIEW_GROUP::GetSize() const
|
||||||
{
|
{
|
||||||
return m_items.size();
|
return m_items.size();
|
||||||
|
|
|
@ -115,6 +115,15 @@ protected:
|
||||||
void onPaint( wxPaintEvent& WXUNUSED( aEvent ) );
|
void onPaint( wxPaintEvent& WXUNUSED( aEvent ) );
|
||||||
void onSize( wxSizeEvent& aEvent );
|
void onSize( wxSizeEvent& aEvent );
|
||||||
void onEvent( wxEvent& aEvent );
|
void onEvent( wxEvent& aEvent );
|
||||||
|
void onEnter( wxEvent& aEvent );
|
||||||
|
void onRefreshTimer ( wxTimerEvent& aEvent );
|
||||||
|
void skipEvent( wxEvent& aEvent );
|
||||||
|
|
||||||
|
static const int MinRefreshPeriod = 17; ///< 60 FPS.
|
||||||
|
|
||||||
|
wxLongLong m_lastRefresh; ///< Last time the panel was refreshed
|
||||||
|
bool m_pendingRefresh;
|
||||||
|
wxTimer m_refreshTimer;
|
||||||
|
|
||||||
KiGfx::GAL* m_gal; ///< Interface for drawing objects on a 2D-surface
|
KiGfx::GAL* m_gal; ///< Interface for drawing objects on a 2D-surface
|
||||||
KiGfx::VIEW* m_view; ///< Stores view settings (scale, center, etc.)
|
KiGfx::VIEW* m_view; ///< Stores view settings (scale, center, etc.)
|
||||||
|
|
|
@ -127,6 +127,11 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saturates the color to a given factor (in HSV model)
|
||||||
|
*/
|
||||||
|
COLOR4D& Saturate( double aFactor );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Brightened
|
* Function Brightened
|
||||||
* Returns a color that is brighter by a given factor, without modifying object.
|
* Returns a color that is brighter by a given factor, without modifying object.
|
||||||
|
@ -180,6 +185,26 @@ public:
|
||||||
return ( r * 0.299 + g * 0.587 + b * 0.117 );
|
return ( r * 0.299 + g * 0.587 + b * 0.117 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function ToHSV()
|
||||||
|
* Converts current color (stored in RGB) to HSV format.
|
||||||
|
*
|
||||||
|
* @param aOutH is conversion result for hue component.
|
||||||
|
* @param aOutS is conversion result for saturation component.
|
||||||
|
* @param aOutV is conversion result for value component.
|
||||||
|
*/
|
||||||
|
void ToHSV( double& aOutH, double& aOutS, double& aOutV ) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function FromHSV()
|
||||||
|
* Changes currently used color to the one given by hue, saturation and value parameters.
|
||||||
|
*
|
||||||
|
* @param aOutH is hue component.
|
||||||
|
* @param aOutS is saturation component.
|
||||||
|
* @param aOutV is value component.
|
||||||
|
*/
|
||||||
|
void FromHSV( double aInH, double aInS, double aInV );
|
||||||
|
|
||||||
/// @brief Equality operator, are two colors equal
|
/// @brief Equality operator, are two colors equal
|
||||||
const bool operator==( const COLOR4D& aColor );
|
const bool operator==( const COLOR4D& aColor );
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,361 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SEG_H
|
||||||
|
#define __SEG_H
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <climits>
|
||||||
|
|
||||||
|
#include <math/vector2d.h>
|
||||||
|
|
||||||
|
#include <boost/optional/optional.hpp>
|
||||||
|
|
||||||
|
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 (x1, y1) and (x2, y2), locally referenced
|
||||||
|
*/
|
||||||
|
SEG ( int x1, int y1, int x2, int y2 ) : a(m_a), b(m_b)
|
||||||
|
{
|
||||||
|
m_a = VECTOR2I(x1, y1);
|
||||||
|
m_b = VECTOR2I(x2, y2);
|
||||||
|
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& seg ): a(m_a), b(m_b)
|
||||||
|
{
|
||||||
|
if (seg.m_is_local)
|
||||||
|
{
|
||||||
|
m_a = seg.m_a;
|
||||||
|
m_b = seg.m_b;
|
||||||
|
a = m_a;
|
||||||
|
b = m_b;
|
||||||
|
m_is_local = true;
|
||||||
|
m_index = -1;
|
||||||
|
} else {
|
||||||
|
a = seg.a;
|
||||||
|
b = seg.b;
|
||||||
|
m_index = seg.m_index;
|
||||||
|
m_is_local = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SEG& operator=(const SEG& seg)
|
||||||
|
{
|
||||||
|
a = seg.a;
|
||||||
|
b = seg.b;
|
||||||
|
m_a = seg.m_a;
|
||||||
|
m_b = seg.m_b;
|
||||||
|
m_index = seg.m_index;
|
||||||
|
m_is_local = seg.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 dist) const;
|
||||||
|
|
||||||
|
// friend std::ostream& operator<<( std::ostream& stream, const SEG& aSeg );
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool ccw ( const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I &c ) 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);
|
||||||
|
/*const VECTOR2I d = aB - aA;
|
||||||
|
ecoord det = d.Dot(d);
|
||||||
|
ecoord dxdy = (ecoord) d.x * d.y;
|
||||||
|
|
||||||
|
ecoord qx =
|
||||||
|
( (extended_type) aA.x * d.y * d.y + (extended_type) d.x * d.x * x - dxdy *
|
||||||
|
(aA.y - y) ) / det;
|
||||||
|
extended_type qy =
|
||||||
|
( (extended_type) aA.y * d.x * d.x + (extended_type) d.y * d.y * y - dxdy *
|
||||||
|
(aA.x - x) ) / det;
|
||||||
|
|
||||||
|
return VECTOR2<T> ( (T) qx, (T) qy );*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 dist = ( p * aP.x + q * aP.y + r ) / sqrt( p * p + q * q );
|
||||||
|
return aDetermineSide ? dist : abs(dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
inline const VECTOR2I SEG::NearestPoint(const VECTOR2I& aP) const
|
||||||
|
{
|
||||||
|
VECTOR2I d = b - a;
|
||||||
|
ecoord l_squared = d.Dot(d);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return a + VECTOR2I(xp, yp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<( std::ostream& aStream, const SEG& aSeg )
|
||||||
|
{
|
||||||
|
if(aSeg.m_is_local)
|
||||||
|
aStream << "[ local " << aSeg.a << " - " << aSeg.b << " ]";
|
||||||
|
return aStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __SEG_H
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHAPE_H
|
||||||
|
#define __SHAPE_H
|
||||||
|
|
||||||
|
#include <math/vector2d.h>
|
||||||
|
#include <math/box2.h>
|
||||||
|
|
||||||
|
#include <geometry/seg.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum ShapeType
|
||||||
|
* Lists all supported shapes
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum ShapeType {
|
||||||
|
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. All SHAPEs implement SHAPE interface.
|
||||||
|
*/
|
||||||
|
class SHAPE {
|
||||||
|
protected:
|
||||||
|
typedef typename 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); };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
* @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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CollideShapes ( const SHAPE *a, const SHAPE *b, int clearance, bool needMTV, VECTOR2I& aMTV );
|
||||||
|
|
||||||
|
#endif // __SHAPE_H
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHAPE_CIRCLE_H
|
||||||
|
#define __SHAPE_CIRCLE_H
|
||||||
|
|
||||||
|
#include "shape.h"
|
||||||
|
|
||||||
|
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() {};
|
||||||
|
|
||||||
|
const BOX2I BBox(int aClearance = 0) const
|
||||||
|
{
|
||||||
|
const VECTOR2I rc (m_radius + aClearance, m_radius + aClearance);
|
||||||
|
return BOX2I (m_center - rc, rc * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Collide(const SEG& aSeg, int aClearance = 0) const
|
||||||
|
{
|
||||||
|
int rc = aClearance + m_radius;
|
||||||
|
return aSeg.Distance(m_center) <= rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetRadius(int aRadius)
|
||||||
|
{
|
||||||
|
m_radius = aRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCenter (const VECTOR2I& aCenter)
|
||||||
|
{
|
||||||
|
m_center = aCenter;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetRadius() const
|
||||||
|
{
|
||||||
|
return m_radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VECTOR2I GetCenter() const
|
||||||
|
{
|
||||||
|
return m_center;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
int m_radius;
|
||||||
|
VECTOR2I m_center;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHAPE_INDEX_H
|
||||||
|
#define __SHAPE_INDEX_H
|
||||||
|
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
|
||||||
|
template <class T> const SHAPE *defaultShapeFunctor( const T aItem )
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// "Normal" iterator interface, for STL algorithms.
|
||||||
|
class iterator {
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator() {};
|
||||||
|
|
||||||
|
iterator( ShapeVecIter aCurrent)
|
||||||
|
: m_current(aCurrent) {};
|
||||||
|
|
||||||
|
iterator(const iterator &b) :
|
||||||
|
m_current(b.m_current) {};
|
||||||
|
|
||||||
|
T operator*() const
|
||||||
|
{
|
||||||
|
return (*m_current).parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator++()
|
||||||
|
{
|
||||||
|
++m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator++(int dummy)
|
||||||
|
{
|
||||||
|
++m_current;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==( const iterator& rhs ) const
|
||||||
|
{
|
||||||
|
return m_current == rhs.m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=( const iterator& rhs ) const
|
||||||
|
{
|
||||||
|
return m_current != rhs.m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterator& operator=(const iterator& rhs)
|
||||||
|
{
|
||||||
|
m_current = rhs.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 &b)
|
||||||
|
: m_end(b.m_end),
|
||||||
|
m_current(b.m_current),
|
||||||
|
m_shape(b.m_shape),
|
||||||
|
m_minDistance(b.m_minDistance),
|
||||||
|
m_exact(b.m_exact),
|
||||||
|
m_refBBox(b.m_refBBox)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
T operator*() const
|
||||||
|
{
|
||||||
|
return (*m_current).parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
query_iterator& operator++()
|
||||||
|
{
|
||||||
|
++m_current;
|
||||||
|
next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
query_iterator& operator++(int dummy)
|
||||||
|
{
|
||||||
|
++m_current;
|
||||||
|
next();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==( const query_iterator& rhs ) const
|
||||||
|
{
|
||||||
|
return m_current == rhs.m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator !=( const query_iterator& rhs ) const
|
||||||
|
{
|
||||||
|
return m_current != rhs.m_current;
|
||||||
|
}
|
||||||
|
|
||||||
|
const query_iterator& operator=(const query_iterator& rhs)
|
||||||
|
{
|
||||||
|
m_end = rhs.m_end;
|
||||||
|
m_current = rhs.m_current;
|
||||||
|
m_shape = rhs.m_shape;
|
||||||
|
m_minDistance = rhs.m_minDistance;
|
||||||
|
m_exact = rhs.m_exact;
|
||||||
|
m_refBBox = rhs.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 &v, bool aExact = true) //const
|
||||||
|
{
|
||||||
|
ShapeVecIter i;
|
||||||
|
int n = 0;
|
||||||
|
VECTOR2I::extended_type minDistSq = (VECTOR2I::extended_type) aMinDistance * aMinDistance;
|
||||||
|
|
||||||
|
BOX2I refBBox = aShape->BBox();
|
||||||
|
|
||||||
|
for(i = m_shapes.begin(); i!=m_shapes.end(); ++i)
|
||||||
|
{
|
||||||
|
if (refBBox.SquaredDistance(i->bbox) <= minDistSq)
|
||||||
|
{
|
||||||
|
if(!aExact || i->shape->Collide(aShape, aMinDistance))
|
||||||
|
{
|
||||||
|
n++;
|
||||||
|
if(!v( i->parent ))
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ShapeVec m_shapes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,531 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHAPE_LINE_CHAIN
|
||||||
|
#define __SHAPE_LINE_CHAIN
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
#include <math/vector2d.h>
|
||||||
|
#include <geometry/shape.h>
|
||||||
|
#include <geometry/seg.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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& a, const VECTOR2I& b):
|
||||||
|
SHAPE (SH_LINE_CHAIN),
|
||||||
|
m_closed(false)
|
||||||
|
{
|
||||||
|
m_points.resize(2);
|
||||||
|
m_points[0] = a;
|
||||||
|
m_points[1] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAPE_LINE_CHAIN(const VECTOR2I& a, const VECTOR2I& b, const VECTOR2I& c):
|
||||||
|
SHAPE (SH_LINE_CHAIN),
|
||||||
|
m_closed(false)
|
||||||
|
{
|
||||||
|
m_points.resize(3);
|
||||||
|
m_points[0] = a;
|
||||||
|
m_points[1] = b;
|
||||||
|
m_points[2] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHAPE_LINE_CHAIN(const VECTOR2I *v, int count):
|
||||||
|
SHAPE (SH_LINE_CHAIN),
|
||||||
|
m_closed(false)
|
||||||
|
{
|
||||||
|
m_points.resize(count);
|
||||||
|
for(int i = 0; i < count ; i++)
|
||||||
|
m_points[i] = *v++;
|
||||||
|
}
|
||||||
|
|
||||||
|
~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 index: 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 index )
|
||||||
|
{
|
||||||
|
if(index < 0)
|
||||||
|
index += SegmentCount();
|
||||||
|
|
||||||
|
if(index == (m_points.size() - 1) && m_closed )
|
||||||
|
return SEG ( m_points[index], m_points[0], index );
|
||||||
|
else
|
||||||
|
return SEG ( m_points[index], m_points[index + 1], index );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function CSegment()
|
||||||
|
*
|
||||||
|
* Returns a read-only segment referencing to the segment (index) in the line chain.
|
||||||
|
* @param index: 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 index ) const
|
||||||
|
{
|
||||||
|
if(index < 0)
|
||||||
|
index += SegmentCount();
|
||||||
|
|
||||||
|
if(index == (m_points.size() - 1) && m_closed )
|
||||||
|
return SEG ( const_cast<VECTOR2I&>(m_points[index]),
|
||||||
|
const_cast<VECTOR2I&>(m_points[0]), index );
|
||||||
|
else
|
||||||
|
return SEG ( const_cast<VECTOR2I&>(m_points[index]),
|
||||||
|
const_cast<VECTOR2I&>(m_points[index + 1]), index );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Point()
|
||||||
|
*
|
||||||
|
* Returns a reference to a given point in the line chain.
|
||||||
|
* @param index index of the point
|
||||||
|
* @return reference to the point
|
||||||
|
*/
|
||||||
|
VECTOR2I& Point ( int index )
|
||||||
|
{
|
||||||
|
if(index < 0)
|
||||||
|
index += PointCount();
|
||||||
|
return m_points[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function CPoint()
|
||||||
|
*
|
||||||
|
* Returns a const reference to a given point in the line chain.
|
||||||
|
* @param index index of the point
|
||||||
|
* @return const reference to the point
|
||||||
|
*/
|
||||||
|
const VECTOR2I& CPoint ( int index ) const
|
||||||
|
{
|
||||||
|
if(index < 0)
|
||||||
|
index += PointCount();
|
||||||
|
return m_points[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @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 x X coordinate of the new point
|
||||||
|
* @param y Y coordinate of the new point
|
||||||
|
*/
|
||||||
|
void Append(int x, int y)
|
||||||
|
{
|
||||||
|
VECTOR2I v(x, y);
|
||||||
|
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 start_index start of the point range to be replaced (inclusive)
|
||||||
|
* @param end_index end of the point range to be replaced (inclusive)
|
||||||
|
* @param aP replacement point
|
||||||
|
*/
|
||||||
|
void Replace( int start_index, int end_index, const VECTOR2I& aP);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Replace()
|
||||||
|
*
|
||||||
|
* Replaces points with indices in range [start_index, end_index] with the points from line chain aLine.
|
||||||
|
* @param start_index start of the point range to be replaced (inclusive)
|
||||||
|
* @param end_index end of the point range to be replaced (inclusive)
|
||||||
|
* @param aLine replacement line chain.
|
||||||
|
*/
|
||||||
|
void Replace( int start_index, int end_index, const SHAPE_LINE_CHAIN& aLine);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Remove()
|
||||||
|
*
|
||||||
|
* Removes the range of points [start_index, end_index] from the line chain.
|
||||||
|
* @param start_index start of the point range to be replaced (inclusive)
|
||||||
|
* @param end_index end of the point range to be replaced (inclusive)
|
||||||
|
*/
|
||||||
|
void Remove( int start_index, int end_index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 start_index start of the point range to be returned (inclusive)
|
||||||
|
* @param end_index end of the point range to be returned (inclusive)
|
||||||
|
* @return cut line chain.
|
||||||
|
*/
|
||||||
|
const SHAPE_LINE_CHAIN Slice( int start_index, int end_index = -1) const;
|
||||||
|
|
||||||
|
|
||||||
|
struct compareOriginDistance {
|
||||||
|
compareOriginDistance( VECTOR2I& aOrigin ):
|
||||||
|
m_origin(aOrigin) {};
|
||||||
|
|
||||||
|
bool operator()(const Intersection &a, const Intersection& b)
|
||||||
|
{
|
||||||
|
return (m_origin - a.p).EuclideanNorm() < (m_origin - b.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& rhs) const
|
||||||
|
{
|
||||||
|
if(PointCount() != rhs.PointCount())
|
||||||
|
return true;
|
||||||
|
for(int i = 0; i < PointCount(); i++)
|
||||||
|
if( CPoint(i) != rhs.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
|
|
@ -0,0 +1,142 @@
|
||||||
|
/*
|
||||||
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 CERN
|
||||||
|
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, you may find one here:
|
||||||
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
||||||
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
||||||
|
* or you may write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SHAPE_RECT_H
|
||||||
|
#define __SHAPE_RECT_H
|
||||||
|
|
||||||
|
#include <geometry/shape.h>
|
||||||
|
#include <geometry/shape_line_chain.h>
|
||||||
|
#include <geometry/shape_circle.h>
|
||||||
|
#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 (x0, y0), width w and height h.
|
||||||
|
*/
|
||||||
|
SHAPE_RECT( int x0, int y0, int w, int h ):
|
||||||
|
SHAPE(SH_RECT), m_p0(x0, y0), m_w(w), m_h(h) {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* Creates a rectangle defined by top-left corner p0, width w and height h.
|
||||||
|
*/
|
||||||
|
SHAPE_RECT( const VECTOR2I &p0, int w, int h ):
|
||||||
|
SHAPE(SH_RECT), m_p0(p0), m_w(w), m_h(h) {};
|
||||||
|
|
||||||
|
/// @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,9 @@ public:
|
||||||
BOX2( const Vec& aPos, const Vec& aSize ) :
|
BOX2( const Vec& aPos, const Vec& aSize ) :
|
||||||
m_Pos( aPos ),
|
m_Pos( aPos ),
|
||||||
m_Size( aSize )
|
m_Size( aSize )
|
||||||
{ }
|
{
|
||||||
|
Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
void SetMaximum()
|
void SetMaximum()
|
||||||
{
|
{
|
||||||
|
@ -416,8 +418,8 @@ public:
|
||||||
{
|
{
|
||||||
ecoord_type x2 = m_Pos.x + m_Size.x;
|
ecoord_type x2 = m_Pos.x + m_Size.x;
|
||||||
ecoord_type y2 = m_Pos.y + m_Size.y;
|
ecoord_type y2 = m_Pos.y + m_Size.y;
|
||||||
ecoord_type xdiff = std::max( aP.x < m_Pos.x ? m_Pos.x - aP.x : m_Pos.x - x2, 0 );
|
ecoord_type xdiff = std::max( aP.x < m_Pos.x ? m_Pos.x - aP.x : m_Pos.x - x2, (ecoord_type)0 );
|
||||||
ecoord_type ydiff = std::max( aP.y < m_Pos.y ? m_Pos.y - aP.y : m_Pos.y - y2, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,12 +50,12 @@ template<> int rescale( int numerator, int value, int denominator )
|
||||||
|
|
||||||
template<> int64_t rescale( int64_t numerator, int64_t value, int64_t denominator )
|
template<> int64_t rescale( int64_t numerator, int64_t value, int64_t denominator )
|
||||||
{
|
{
|
||||||
uint64_t r = 0;
|
int64_t r = 0;
|
||||||
int64_t sign = ( ( numerator < 0) ? -1 : 1 ) * ( denominator < 0 ? - 1: 1 ) * (value < 0 ? - 1 : 1);
|
int64_t sign = ( ( numerator < 0) ? -1 : 1 ) * ( denominator < 0 ? - 1: 1 ) * (value < 0 ? - 1 : 1);
|
||||||
|
|
||||||
uint64_t a = abs( numerator );
|
int64_t a = std::abs( numerator );
|
||||||
uint64_t b = abs( value );
|
int64_t b = std::abs( value );
|
||||||
uint64_t c = abs( denominator );
|
int64_t c = std::abs( denominator );
|
||||||
|
|
||||||
r = c / 2;
|
r = c / 2;
|
||||||
|
|
||||||
|
@ -77,14 +77,14 @@ template<> int64_t rescale( int64_t numerator, int64_t value, int64_t denominato
|
||||||
a0 = a0 * b0 + t1a;
|
a0 = a0 * b0 + t1a;
|
||||||
a1 = a1 * b1 + (t1 >> 32) + (a0 < t1a);
|
a1 = a1 * b1 + (t1 >> 32) + (a0 < t1a);
|
||||||
a0 += r;
|
a0 += r;
|
||||||
a1 += a0 < r;
|
a1 += ((uint64_t)a0) < r;
|
||||||
|
|
||||||
for( i = 63; i >= 0; i-- )
|
for( i = 63; i >= 0; i-- )
|
||||||
{
|
{
|
||||||
a1 += a1 + ( (a0 >> i) & 1 );
|
a1 += a1 + ( (a0 >> i) & 1 );
|
||||||
t1 += t1;
|
t1 += t1;
|
||||||
|
|
||||||
if( c <= a1 )
|
if( (uint64_t)c <= a1 )
|
||||||
{
|
{
|
||||||
a1 -= c;
|
a1 -= c;
|
||||||
t1++;
|
t1++;
|
||||||
|
|
|
@ -54,6 +54,8 @@ template <>
|
||||||
struct VECTOR2_TRAITS<int>
|
struct VECTOR2_TRAITS<int>
|
||||||
{
|
{
|
||||||
typedef int64_t extended_type;
|
typedef int64_t extended_type;
|
||||||
|
static const extended_type ECOORD_MAX = 0x7fffffffffffffffULL;
|
||||||
|
static const extended_type ECOORD_MIN = 0x8000000000000000ULL;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Forward declarations for template friends
|
// Forward declarations for template friends
|
||||||
|
@ -123,6 +125,15 @@ public:
|
||||||
*/
|
*/
|
||||||
T EuclideanNorm() const;
|
T EuclideanNorm() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function Squared Euclidean Norm
|
||||||
|
* computes the squared euclidean norm of the vector, which is defined as (x ** 2 + y ** 2).
|
||||||
|
* It is used to calculate the length of the vector.
|
||||||
|
* @return Scalar, the euclidean norm
|
||||||
|
*/
|
||||||
|
extended_type SquaredEuclideanNorm() const;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Perpendicular
|
* Function Perpendicular
|
||||||
* computes the perpendicular vector
|
* computes the perpendicular vector
|
||||||
|
@ -130,40 +141,6 @@ public:
|
||||||
*/
|
*/
|
||||||
VECTOR2<T> Perpendicular() const;
|
VECTOR2<T> Perpendicular() const;
|
||||||
|
|
||||||
/**
|
|
||||||
* Function LineProjection
|
|
||||||
* computes the perpendicular projection point of self on a line
|
|
||||||
* going through aA and aB points.
|
|
||||||
* @return Projected point
|
|
||||||
*/
|
|
||||||
VECTOR2<T> LineProjection( const VECTOR2<T>& aA, const VECTOR2<T>& aB ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function LineSide
|
|
||||||
* determines on which side of directed line passing via points aEnd
|
|
||||||
* and a start aStart we are.
|
|
||||||
* @return: < 0: left, 0 : on the line, > 0 : right
|
|
||||||
*/
|
|
||||||
int LineSide( const VECTOR2<T>& aStart, const VECTOR2<T>& aEnd ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function LineDistance
|
|
||||||
* returns the closest Euclidean distance to a line defined by points
|
|
||||||
* aStart and aEnd.
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
T LineDistance( const VECTOR2<T>& aStart, const VECTOR2<T>& aEnd,
|
|
||||||
bool aDetermineSide = false ) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function ClosestSegmentPoint
|
|
||||||
* returns the closest point on a line segment defined by aStart and aEnd.
|
|
||||||
* @return: our point
|
|
||||||
*/
|
|
||||||
VECTOR2<T> ClosestSegmentPoint( const VECTOR2<T>& aStart, const VECTOR2<T>& aEnd ) const;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function Resize
|
* Function Resize
|
||||||
* returns a vector of the same direction, but length specified in aNewLength
|
* returns a vector of the same direction, but length specified in aNewLength
|
||||||
|
@ -308,6 +285,13 @@ T VECTOR2<T>::EuclideanNorm() const
|
||||||
return sqrt( (extended_type) x * x + (extended_type) y * y );
|
return sqrt( (extended_type) x * x + (extended_type) y * y );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename VECTOR2<T>::extended_type VECTOR2<T>::SquaredEuclideanNorm() const
|
||||||
|
{
|
||||||
|
return (extended_type)x * x + (extended_type) y * y ;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
double VECTOR2<T>::Angle() const
|
double VECTOR2<T>::Angle() const
|
||||||
|
@ -367,89 +351,6 @@ VECTOR2<T>& VECTOR2<T>::operator-=( const T& aScalar )
|
||||||
y -= aScalar;
|
y -= aScalar;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
int VECTOR2<T>::LineSide( const VECTOR2<T>& aStart, const VECTOR2<T>& aEnd ) const
|
|
||||||
{
|
|
||||||
VECTOR2<T> d = aEnd - aStart;
|
|
||||||
VECTOR2<T> ap = *this - aStart;
|
|
||||||
|
|
||||||
extended_type det = (extended_type) d.x * (extended_type) ap.y
|
|
||||||
- (extended_type) d.y * (extended_type) ap.x;
|
|
||||||
|
|
||||||
return det < 0 ? -1 : (det > 0 ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
VECTOR2<T> VECTOR2<T>::LineProjection( const VECTOR2<T>& aA, const VECTOR2<T>& aB ) const
|
|
||||||
{
|
|
||||||
const VECTOR2<T> d = aB - aA;
|
|
||||||
extended_type det = (extended_type) d.x * d.x + d.y * (extended_type) d.y;
|
|
||||||
extended_type dxdy = (extended_type) d.x * d.y;
|
|
||||||
extended_type qx =
|
|
||||||
( (extended_type) aA.x * d.y * d.y + (extended_type) d.x * d.x * x - dxdy *
|
|
||||||
(aA.y - y) ) / det;
|
|
||||||
extended_type qy =
|
|
||||||
( (extended_type) aA.y * d.x * d.x + (extended_type) d.y * d.y * y - dxdy *
|
|
||||||
(aA.x - x) ) / det;
|
|
||||||
|
|
||||||
return VECTOR2<T> ( (T) qx, (T) qy );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
T VECTOR2<T>::LineDistance( const VECTOR2<T>& aStart, const VECTOR2<T>& aEnd,
|
|
||||||
bool aDetermineSide ) const
|
|
||||||
{
|
|
||||||
extended_type a = aStart.y - aEnd.y;
|
|
||||||
extended_type b = aEnd.x - aStart.x;
|
|
||||||
extended_type c = -a * aStart.x - b * aStart.y;
|
|
||||||
|
|
||||||
T dist = ( a * x + b * y + c ) / sqrt( a * a + b * b );
|
|
||||||
return aDetermineSide ? dist : abs( dist );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
VECTOR2<T> VECTOR2<T>::ClosestSegmentPoint( const VECTOR2<T>& aStart,
|
|
||||||
const VECTOR2<T>& aEnd ) const
|
|
||||||
{
|
|
||||||
VECTOR2<T> d = (aEnd - aStart);
|
|
||||||
extended_type l_squared = (extended_type) d.x * d.x + (extended_type) d.y * d.y;
|
|
||||||
|
|
||||||
|
|
||||||
if( l_squared == 0 )
|
|
||||||
{
|
|
||||||
return aStart;
|
|
||||||
}
|
|
||||||
|
|
||||||
extended_type t =
|
|
||||||
(extended_type) (x - aStart.x) * (extended_type) d.x +
|
|
||||||
(extended_type) (y - aStart.y) * (extended_type) d.y;
|
|
||||||
|
|
||||||
if( t < 0 )
|
|
||||||
{
|
|
||||||
return aStart;
|
|
||||||
}
|
|
||||||
else if( t > l_squared )
|
|
||||||
{
|
|
||||||
return aEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
double xp = (double) t * (double) d.x / (double) l_squared;
|
|
||||||
double yp = (double) t * (double) d.y / (double) l_squared;
|
|
||||||
|
|
||||||
/*VECTOR2<T> proj = aStart + VECTOR2<T> ( ( t * (extended_type) d.x / l_squared ),
|
|
||||||
( t * ( extended_type) d.y / l_squared ) );*/
|
|
||||||
|
|
||||||
VECTOR2<T> proj = aStart + VECTOR2<T> ( (T) xp, (T) yp );
|
|
||||||
|
|
||||||
return proj;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
VECTOR2<T> VECTOR2<T>::Rotate( double aAngle ) const
|
VECTOR2<T> VECTOR2<T>::Rotate( double aAngle ) const
|
||||||
{
|
{
|
||||||
|
@ -464,14 +365,15 @@ VECTOR2<T> VECTOR2<T>::Rotate( double aAngle ) const
|
||||||
template <class T>
|
template <class T>
|
||||||
VECTOR2<T> VECTOR2<T>::Resize( T aNewLength ) const
|
VECTOR2<T> VECTOR2<T>::Resize( T aNewLength ) const
|
||||||
{
|
{
|
||||||
if( x == 0 && y == 0 )
|
if(x == 0 && y == 0)
|
||||||
return VECTOR2<T> ( 0, 0 );
|
return VECTOR2<T> (0, 0);
|
||||||
|
|
||||||
T l = this->EuclideanNorm();
|
extended_type l_sq_current = (extended_type)this->x * this->x + (extended_type)this->y * this->y;
|
||||||
|
extended_type l_sq_new = (extended_type) aNewLength * aNewLength;
|
||||||
|
|
||||||
return VECTOR2<T> (
|
return VECTOR2<T> (
|
||||||
rescale( aNewLength, x, l ),
|
(this->x < 0 ? -1 : 1 ) * sqrt(rescale(l_sq_new, (extended_type) x * x, l_sq_current)),
|
||||||
rescale( aNewLength, y, l ) );
|
(this->y < 0 ? -1 : 1 ) * sqrt(rescale(l_sq_new, (extended_type) y * y, l_sq_current)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,8 @@ private:
|
||||||
bool handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion );
|
bool handleMouseButton( wxEvent& aEvent, int aIndex, bool aMotion );
|
||||||
bool handlePopupMenu( wxEvent& aEvent );
|
bool handlePopupMenu( wxEvent& aEvent );
|
||||||
|
|
||||||
|
wxPoint getCurrentMousePos() const;
|
||||||
|
|
||||||
int decodeModifiers( const wxKeyboardState* aState ) const;
|
int decodeModifiers( const wxKeyboardState* aState ) const;
|
||||||
|
|
||||||
struct ButtonState;
|
struct ButtonState;
|
||||||
|
|
|
@ -443,6 +443,15 @@ public:
|
||||||
return ( m_layers.at( aLayer ).target == TARGET_CACHED );
|
return ( m_layers.at( aLayer ).target == TARGET_CACHED );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function MarkDirty()
|
||||||
|
* Forces redraw of view on the next rendering.
|
||||||
|
*/
|
||||||
|
void MarkDirty()
|
||||||
|
{
|
||||||
|
for( int i = 0; i < TARGETS_NUMBER; ++i )
|
||||||
|
m_dirtyTargets[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
static const int VIEW_MAX_LAYERS = 128; ///* maximum number of layers that may be shown
|
static const int VIEW_MAX_LAYERS = 128; ///* maximum number of layers that may be shown
|
||||||
|
|
||||||
|
|
|
@ -130,6 +130,23 @@ public:
|
||||||
m_layer = aLayer;
|
m_layer = aLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function FreeItems()
|
||||||
|
* Frees all the items that were added to the group.
|
||||||
|
*/
|
||||||
|
void FreeItems();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function GetView()
|
||||||
|
* Returns pointer to the VIEW instance used by items.
|
||||||
|
*
|
||||||
|
* @return Pointer to the VIEW instance.
|
||||||
|
*/
|
||||||
|
KiGfx::VIEW *GetView() const
|
||||||
|
{
|
||||||
|
return m_view;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// These functions cannot be used with VIEW_GROUP as they are intended only to work with
|
/// These functions cannot be used with VIEW_GROUP as they are intended only to work with
|
||||||
/// singular VIEW_ITEMs (there is only one-to-one relation between item/layer combination and
|
/// singular VIEW_ITEMs (there is only one-to-one relation between item/layer combination and
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
add_definitions(-DPCBNEW)
|
add_definitions(-DPCBNEW)
|
||||||
|
add_subdirectory(router)
|
||||||
|
|
||||||
if (KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES)
|
if (KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES)
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/scripting)
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/scripting)
|
||||||
|
@ -117,6 +118,7 @@ set(PCBNEW_AUTOROUTER_SRCS
|
||||||
autorouter/work.cpp
|
autorouter/work.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
set(PCBNEW_CLASS_SRCS
|
set(PCBNEW_CLASS_SRCS
|
||||||
tool_modview.cpp
|
tool_modview.cpp
|
||||||
modview.cpp
|
modview.cpp
|
||||||
|
@ -325,6 +327,7 @@ if (KICAD_SCRIPTING_MODULES)
|
||||||
swig_link_libraries(pcbnew
|
swig_link_libraries(pcbnew
|
||||||
3d-viewer
|
3d-viewer
|
||||||
pcbcommon
|
pcbcommon
|
||||||
|
pnsrouter
|
||||||
common
|
common
|
||||||
pcad2kicadpcb
|
pcad2kicadpcb
|
||||||
polygon
|
polygon
|
||||||
|
@ -421,6 +424,7 @@ endif(APPLE)
|
||||||
target_link_libraries(pcbnew
|
target_link_libraries(pcbnew
|
||||||
3d-viewer
|
3d-viewer
|
||||||
pcbcommon
|
pcbcommon
|
||||||
|
pnsrouter
|
||||||
common
|
common
|
||||||
pcad2kicadpcb
|
pcad2kicadpcb
|
||||||
polygon
|
polygon
|
||||||
|
|
|
@ -305,6 +305,11 @@ void PCB_EDIT_FRAME::ReCreateMenuBar()
|
||||||
_( "Interactive selection and drag&drop tool." ),
|
_( "Interactive selection and drag&drop tool." ),
|
||||||
KiBitmap( tools_xpm ) );
|
KiBitmap( tools_xpm ) );
|
||||||
|
|
||||||
|
AddMenuItem( editMenu, ID_PNS_ROUTER_TOOL,
|
||||||
|
_( "Interactive router" ),
|
||||||
|
_( "Interactive router drag&drop tool." ),
|
||||||
|
KiBitmap( tools_xpm ) );
|
||||||
|
|
||||||
/** Create View menu **/
|
/** Create View menu **/
|
||||||
wxMenu* viewMenu = new wxMenu;
|
wxMenu* viewMenu = new wxMenu;
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,12 @@ void PCB_RENDER_SETTINGS::update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const COLOR4D& PCB_RENDER_SETTINGS::GetLayerColor( int aLayer ) const
|
||||||
|
{
|
||||||
|
return m_layerColors[aLayer];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PCB_PAINTER::PCB_PAINTER( GAL* aGal ) :
|
PCB_PAINTER::PCB_PAINTER( GAL* aGal ) :
|
||||||
PAINTER( aGal )
|
PAINTER( aGal )
|
||||||
{
|
{
|
||||||
|
|
|
@ -89,6 +89,8 @@ public:
|
||||||
/// @copydoc RENDER_SETTINGS::GetColor()
|
/// @copydoc RENDER_SETTINGS::GetColor()
|
||||||
virtual const COLOR4D& GetColor( const VIEW_ITEM* aItem, int aLayer ) const;
|
virtual const COLOR4D& GetColor( const VIEW_ITEM* aItem, int aLayer ) const;
|
||||||
|
|
||||||
|
const COLOR4D& GetLayerColor( int aLayer ) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// @copydoc RENDER_SETTINGS::Update()
|
/// @copydoc RENDER_SETTINGS::Update()
|
||||||
void update();
|
void update();
|
||||||
|
|
|
@ -122,6 +122,8 @@ BEGIN_EVENT_TABLE( PCB_EDIT_FRAME, PCB_BASE_FRAME )
|
||||||
/* Tom's hacks start */
|
/* Tom's hacks start */
|
||||||
EVT_MENU ( ID_SELECTION_TOOL, PCB_EDIT_FRAME::onGenericCommand )
|
EVT_MENU ( ID_SELECTION_TOOL, PCB_EDIT_FRAME::onGenericCommand )
|
||||||
EVT_TOOL ( ID_SELECTION_TOOL, PCB_EDIT_FRAME::onGenericCommand )
|
EVT_TOOL ( ID_SELECTION_TOOL, PCB_EDIT_FRAME::onGenericCommand )
|
||||||
|
EVT_MENU ( ID_PNS_ROUTER_TOOL, PCB_EDIT_FRAME::onGenericCommand )
|
||||||
|
EVT_TOOL ( ID_PNS_ROUTER_TOOL, PCB_EDIT_FRAME::onGenericCommand )
|
||||||
/* Tom's hacks end */
|
/* Tom's hacks end */
|
||||||
|
|
||||||
EVT_MENU( ID_PCB_DRAWINGS_WIDTHS_SETUP, PCB_EDIT_FRAME::OnConfigurePcbOptions )
|
EVT_MENU( ID_PCB_DRAWINGS_WIDTHS_SETUP, PCB_EDIT_FRAME::OnConfigurePcbOptions )
|
||||||
|
@ -752,7 +754,7 @@ void PCB_EDIT_FRAME::setHighContrastLayer( LAYER_NUM aLayer )
|
||||||
KiGfx::VIEW* view = m_galCanvas->GetView();
|
KiGfx::VIEW* view = m_galCanvas->GetView();
|
||||||
KiGfx::RENDER_SETTINGS* rSettings = view->GetPainter()->GetSettings();
|
KiGfx::RENDER_SETTINGS* rSettings = view->GetPainter()->GetSettings();
|
||||||
|
|
||||||
if( DisplayOpt.ContrastModeDisplay )
|
// if( DisplayOpt.ContrastModeDisplay )
|
||||||
{
|
{
|
||||||
view->ClearTopLayers();
|
view->ClearTopLayers();
|
||||||
view->SetTopLayer( aLayer );
|
view->SetTopLayer( aLayer );
|
||||||
|
|
|
@ -366,7 +366,8 @@ enum pcbnew_ids
|
||||||
ID_FOOTPRINT_WIZARD_SELECT_WIZARD,
|
ID_FOOTPRINT_WIZARD_SELECT_WIZARD,
|
||||||
ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD,
|
ID_FOOTPRINT_WIZARD_EXPORT_TO_BOARD,
|
||||||
|
|
||||||
ID_SELECTION_TOOL
|
ID_SELECTION_TOOL,
|
||||||
|
ID_PNS_ROUTER_TOOL
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PCBNEW_ID_H_
|
#endif // PCBNEW_ID_H_
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
You'll see the P&S router sources here, but just not right now.
|
||||||
|
We are still dealing with some non-technical issues that should be solved by the next week.
|
||||||
|
|
||||||
|
Tom
|
|
@ -36,16 +36,18 @@
|
||||||
|
|
||||||
#include "selection_tool.h"
|
#include "selection_tool.h"
|
||||||
#include "move_tool.h"
|
#include "move_tool.h"
|
||||||
|
#include <router/router_tool.h>
|
||||||
|
|
||||||
void PCB_EDIT_FRAME::setupTools()
|
void PCB_EDIT_FRAME::setupTools()
|
||||||
{
|
{
|
||||||
// Create the manager and dispatcher. Route draw panel events to the dispatcher
|
// Create the manager and dispatcher & route draw panel events to the dispatcher
|
||||||
m_toolManager = new TOOL_MANAGER;
|
m_toolManager = new TOOL_MANAGER;
|
||||||
m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager, this );
|
m_toolDispatcher = new TOOL_DISPATCHER( m_toolManager, this );
|
||||||
m_galCanvas->SetEventDispatcher( m_toolDispatcher );
|
m_galCanvas->SetEventDispatcher( m_toolDispatcher );
|
||||||
|
|
||||||
// Register tools
|
// Register tools.
|
||||||
m_toolManager->RegisterTool( new SELECTION_TOOL );
|
m_toolManager->RegisterTool( new SELECTION_TOOL );
|
||||||
|
m_toolManager->RegisterTool( new ROUTER_TOOL );
|
||||||
m_toolManager->RegisterTool( new MOVE_TOOL );
|
m_toolManager->RegisterTool( new MOVE_TOOL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue