pcbnew: Adding arcs to PNS
This is allows ARCs in tracks to be synchronized with the PNS router. Note this does not yet include the UI components to route curved traces
This commit is contained in:
parent
3af868e3d1
commit
8c19b4b6ae
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2009-2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
||||
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -26,7 +26,6 @@
|
|||
#define BOARD_DESIGN_SETTINGS_H_
|
||||
|
||||
#include <class_pad.h>
|
||||
#include <class_track.h>
|
||||
#include <netclass.h>
|
||||
#include <config_params.h>
|
||||
#include <board_stackup_manager/class_board_stackup.h>
|
||||
|
@ -167,6 +166,8 @@ enum
|
|||
LAYER_CLASS_COUNT
|
||||
};
|
||||
|
||||
// forward declaration from class_track.h
|
||||
enum class VIATYPE : int;
|
||||
|
||||
/**
|
||||
* BOARD_DESIGN_SETTINGS
|
||||
|
|
|
@ -5,6 +5,7 @@ set( KIMATH_SRCS
|
|||
src/trigo.cpp
|
||||
|
||||
src/geometry/convex_hull.cpp
|
||||
src/geometry/direction_45.cpp
|
||||
src/geometry/geometry_utils.cpp
|
||||
src/geometry/polygon_test_point_inside.cpp
|
||||
src/geometry/seg.cpp
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2013-2015 CERN
|
||||
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* Copyright (C) 2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2017-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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
|
||||
|
@ -43,7 +43,7 @@ public:
|
|||
* Represents available directions - there are 8 of them, as on a rectilinear map (north = up) +
|
||||
* an extra undefined direction, reserved for traces that don't respect 45-degree routing regime.
|
||||
*/
|
||||
enum Directions
|
||||
enum Directions : int
|
||||
{
|
||||
N = 0,
|
||||
NE = 1,
|
||||
|
@ -53,6 +53,7 @@ public:
|
|||
SW = 5,
|
||||
W = 6,
|
||||
NW = 7,
|
||||
LAST = 8,
|
||||
UNDEFINED = -1
|
||||
};
|
||||
|
||||
|
@ -70,13 +71,14 @@ public:
|
|||
ANG_UNDEFINED = 0x20
|
||||
};
|
||||
|
||||
DIRECTION_45( Directions aDir = UNDEFINED ) : m_dir( aDir ) {}
|
||||
DIRECTION_45( Directions aDir = UNDEFINED ) : m_dir( aDir ), m_90deg( false ) {}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param aVec vector, whose direction will be translated into a DIRECTION_45.
|
||||
*/
|
||||
DIRECTION_45( const VECTOR2I& aVec )
|
||||
DIRECTION_45( const VECTOR2I &aVec, bool a90 = false ) :
|
||||
m_90deg( a90 )
|
||||
{
|
||||
construct_( aVec );
|
||||
}
|
||||
|
@ -85,7 +87,8 @@ public:
|
|||
* Constructor
|
||||
* @param aSeg segment, whose direction will be translated into a DIRECTION_45.
|
||||
*/
|
||||
DIRECTION_45( const SEG& aSeg )
|
||||
DIRECTION_45( const SEG& aSeg, bool a90 = false ) :
|
||||
m_90deg( a90 )
|
||||
{
|
||||
construct_( aSeg.B - aSeg.A );
|
||||
}
|
||||
|
@ -198,51 +201,13 @@ public:
|
|||
* @param aP0 starting point
|
||||
* @param aP1 ending point
|
||||
* @param aStartDiagonal whether the first segment has to be diagonal
|
||||
* @param aRadius is the radius of curvature for rounding. If =0, do not insert arcs
|
||||
* @return the trace
|
||||
*/
|
||||
const SHAPE_LINE_CHAIN BuildInitialTrace( const VECTOR2I& aP0,
|
||||
const VECTOR2I& aP1,
|
||||
bool aStartDiagonal = false ) const
|
||||
{
|
||||
int w = abs( aP1.x - aP0.x );
|
||||
int h = abs( aP1.y - aP0.y );
|
||||
int sw = sign( aP1.x - aP0.x );
|
||||
int sh = sign( aP1.y - aP0.y );
|
||||
|
||||
VECTOR2I mp0, mp1;
|
||||
|
||||
// we are more horizontal than vertical?
|
||||
if( w > h )
|
||||
{
|
||||
mp0 = VECTOR2I( ( w - h ) * sw, 0 ); // direction: E
|
||||
mp1 = VECTOR2I( h * sw, h * sh ); // direction: NE
|
||||
}
|
||||
else
|
||||
{
|
||||
mp0 = VECTOR2I( 0, sh * ( h - w ) ); // direction: N
|
||||
mp1 = VECTOR2I( sw * w, sh * w ); // direction: NE
|
||||
}
|
||||
|
||||
bool start_diagonal;
|
||||
|
||||
if( m_dir == UNDEFINED )
|
||||
start_diagonal = aStartDiagonal;
|
||||
else
|
||||
start_diagonal = IsDiagonal();
|
||||
|
||||
SHAPE_LINE_CHAIN pl;
|
||||
|
||||
pl.Append( aP0 );
|
||||
|
||||
if( start_diagonal )
|
||||
pl.Append( aP0 + mp1 );
|
||||
else
|
||||
pl.Append( aP0 + mp0 );
|
||||
|
||||
pl.Append( aP1 );
|
||||
pl.Simplify();
|
||||
return pl;
|
||||
}
|
||||
bool aStartDiagonal = false,
|
||||
int aMaxRadius = 0 ) const;
|
||||
|
||||
bool operator==( const DIRECTION_45& aOther ) const
|
||||
{
|
||||
|
@ -258,14 +223,19 @@ public:
|
|||
* Function Right()
|
||||
*
|
||||
* Returns the direction on the right side of this (i.e. turns right
|
||||
* by 45 deg)
|
||||
* by 45 or 90 deg)
|
||||
*/
|
||||
const DIRECTION_45 Right() const
|
||||
{
|
||||
DIRECTION_45 r;
|
||||
|
||||
if ( m_dir != UNDEFINED )
|
||||
r.m_dir = static_cast<Directions>( ( m_dir + 1 ) % 8 );
|
||||
{
|
||||
if( m_90deg )
|
||||
r.m_dir = static_cast<Directions>( ( m_dir + 2 ) % LAST );
|
||||
else
|
||||
r.m_dir = static_cast<Directions>( ( m_dir + 1 ) % LAST );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -274,19 +244,19 @@ public:
|
|||
* Function Left()
|
||||
*
|
||||
* Returns the direction on the left side of this (i.e. turns left
|
||||
* by 45 deg)
|
||||
* by 45 or 90 deg)
|
||||
*/
|
||||
const DIRECTION_45 Left() const
|
||||
{
|
||||
DIRECTION_45 l;
|
||||
|
||||
if ( m_dir == UNDEFINED )
|
||||
return l;
|
||||
|
||||
if( m_dir == N )
|
||||
l.m_dir = NW;
|
||||
if ( m_dir != UNDEFINED )
|
||||
{
|
||||
if( m_90deg )
|
||||
l.m_dir = static_cast<Directions>( ( m_dir + LAST - 2 ) % LAST );
|
||||
else
|
||||
l.m_dir = static_cast<Directions>( m_dir - 1 );
|
||||
l.m_dir = static_cast<Directions>( ( m_dir + LAST - 1 ) % LAST );
|
||||
}
|
||||
|
||||
return l;
|
||||
}
|
||||
|
@ -344,11 +314,11 @@ private:
|
|||
|
||||
int dir = ( mag + 22.5 ) / 45.0;
|
||||
|
||||
if( dir >= 8 )
|
||||
dir = dir - 8;
|
||||
if( dir >= LAST )
|
||||
dir -= LAST;
|
||||
|
||||
if( dir < 0 )
|
||||
dir = dir + 8;
|
||||
dir += LAST;
|
||||
|
||||
m_dir = (Directions) dir;
|
||||
|
||||
|
@ -357,6 +327,9 @@ private:
|
|||
|
||||
///> our actual direction
|
||||
Directions m_dir;
|
||||
|
||||
///> Are we routing on 45 or 90 degree increments
|
||||
bool m_90deg;
|
||||
};
|
||||
|
||||
#endif // DIRECTION45_H
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 CERN
|
||||
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -50,6 +51,7 @@ public:
|
|||
SHAPE( SH_ARC ), m_p0( aArcStartPoint ), m_pc( aArcCenter ), m_centralAngle( aCenterAngle ),
|
||||
m_width( aWidth )
|
||||
{
|
||||
update_bbox();
|
||||
}
|
||||
|
||||
SHAPE_ARC( const SHAPE_ARC& aOther )
|
||||
|
@ -59,6 +61,7 @@ public:
|
|||
m_pc = aOther.m_pc;
|
||||
m_centralAngle = aOther.m_centralAngle;
|
||||
m_width = aOther.m_width;
|
||||
m_bbox = aOther.m_bbox;
|
||||
}
|
||||
|
||||
~SHAPE_ARC() {}
|
||||
|
@ -70,6 +73,7 @@ public:
|
|||
|
||||
const VECTOR2I& GetP0() const { return m_p0; }
|
||||
const VECTOR2I GetP1() const;
|
||||
const VECTOR2I GetArcMid() const;
|
||||
const VECTOR2I& GetCenter() const { return m_pc; }
|
||||
|
||||
const BOX2I BBox( int aClearance = 0 ) const override;
|
||||
|
@ -96,6 +100,7 @@ public:
|
|||
{
|
||||
m_p0 += aVector;
|
||||
m_pc += aVector;
|
||||
update_bbox();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,6 +119,7 @@ public:
|
|||
|
||||
m_pc += aCenter;
|
||||
m_p0 += aCenter;
|
||||
update_bbox();
|
||||
}
|
||||
|
||||
void Mirror( bool aX = true, bool aY = false, const VECTOR2I& aVector = { 0, 0 } )
|
||||
|
@ -131,6 +137,8 @@ public:
|
|||
m_pc.y = -m_pc.y + 2 * aVector.y;
|
||||
m_centralAngle = - m_centralAngle;
|
||||
}
|
||||
|
||||
update_bbox();
|
||||
}
|
||||
|
||||
int GetRadius() const;
|
||||
|
@ -176,11 +184,14 @@ private:
|
|||
(ecoord) ( aB.y - aA.y ) * ( aC.x - aA.x );
|
||||
}
|
||||
|
||||
void update_bbox();
|
||||
|
||||
|
||||
VECTOR2I m_p0, m_pc;
|
||||
double m_centralAngle;
|
||||
|
||||
int m_width;
|
||||
BOX2I m_bbox;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2013 CERN
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
* Copyright (C) 2013-2019
|
||||
* Copyright (C) 2013-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -93,8 +93,8 @@ public:
|
|||
m_shapes( aShape.m_shapes ),
|
||||
m_arcs( aShape.m_arcs ),
|
||||
m_closed( aShape.m_closed ),
|
||||
m_bbox( aShape.m_bbox ),
|
||||
m_width( aShape.m_width )
|
||||
m_width( aShape.m_width ),
|
||||
m_bbox( aShape.m_bbox )
|
||||
{}
|
||||
|
||||
SHAPE_LINE_CHAIN( const std::vector<wxPoint>& aV, bool aClosed = false )
|
||||
|
@ -115,8 +115,20 @@ public:
|
|||
m_shapes = std::vector<ssize_t>( aV.size(), ssize_t( SHAPE_IS_PT ) );
|
||||
}
|
||||
|
||||
SHAPE_LINE_CHAIN( const ClipperLib::Path& aPath )
|
||||
: SHAPE( SH_LINE_CHAIN ), m_closed( true ), m_width( 0 )
|
||||
SHAPE_LINE_CHAIN( const SHAPE_ARC& aArc, bool aClosed = false )
|
||||
: SHAPE( SH_LINE_CHAIN ),
|
||||
m_closed( aClosed ),
|
||||
m_width( 0 )
|
||||
{
|
||||
m_points = aArc.ConvertToPolyline().CPoints();
|
||||
m_arcs.emplace_back( aArc );
|
||||
m_shapes = std::vector<ssize_t>( m_points.size(), 0 );
|
||||
}
|
||||
|
||||
SHAPE_LINE_CHAIN( const ClipperLib::Path& aPath ) :
|
||||
SHAPE( SH_LINE_CHAIN ),
|
||||
m_closed( true ),
|
||||
m_width( 0 )
|
||||
{
|
||||
m_points.reserve( aPath.size() );
|
||||
m_shapes = std::vector<ssize_t>( aPath.size(), ssize_t( SHAPE_IS_PT ) );
|
||||
|
@ -298,6 +310,22 @@ public:
|
|||
return m_points[PointCount() - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the vector of stored arcs
|
||||
*/
|
||||
const std::vector<SHAPE_ARC>& CArcs() const
|
||||
{
|
||||
return m_arcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the vector of values indicating shape type and location
|
||||
*/
|
||||
const std::vector<ssize_t>& CShapes() const
|
||||
{
|
||||
return m_shapes;
|
||||
}
|
||||
|
||||
/// @copydoc SHAPE::BBox()
|
||||
const BOX2I BBox( int aClearance = 0 ) const override
|
||||
{
|
||||
|
@ -695,7 +723,33 @@ public:
|
|||
|
||||
double Area() const;
|
||||
|
||||
size_t ArcCount() const
|
||||
{
|
||||
return m_arcs.size();
|
||||
}
|
||||
|
||||
ssize_t ArcIndex( size_t aSegment ) const
|
||||
{
|
||||
if( aSegment >= m_shapes.size() )
|
||||
return SHAPE_IS_PT;
|
||||
|
||||
return m_shapes[aSegment];
|
||||
}
|
||||
|
||||
const SHAPE_ARC& Arc( size_t aArc ) const
|
||||
{
|
||||
return m_arcs[aArc];
|
||||
}
|
||||
|
||||
bool isArc( size_t aSegment ) const
|
||||
{
|
||||
return aSegment < m_shapes.size() && m_shapes[aSegment] != SHAPE_IS_PT;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
constexpr static ssize_t SHAPE_IS_PT = -1;
|
||||
|
||||
/// array of vertices
|
||||
std::vector<VECTOR2I> m_points;
|
||||
|
||||
|
@ -705,7 +759,6 @@ private:
|
|||
* If the value is -1, the point is just a point
|
||||
*/
|
||||
std::vector<ssize_t> m_shapes;
|
||||
constexpr static ssize_t SHAPE_IS_PT = -1;
|
||||
|
||||
std::vector<SHAPE_ARC> m_arcs;
|
||||
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.or/licenses/>.
|
||||
*/
|
||||
|
||||
#include <geometry/direction45.h>
|
||||
|
||||
const SHAPE_LINE_CHAIN DIRECTION_45::BuildInitialTrace( const VECTOR2I& aP0, const VECTOR2I& aP1,
|
||||
bool aStartDiagonal, int aMaxRadius ) const
|
||||
{
|
||||
bool start_diagonal;
|
||||
|
||||
if( m_dir == UNDEFINED )
|
||||
start_diagonal = aStartDiagonal;
|
||||
else
|
||||
start_diagonal = IsDiagonal();
|
||||
|
||||
int w = abs( aP1.x - aP0.x );
|
||||
int h = abs( aP1.y - aP0.y );
|
||||
int sw = sign( aP1.x - aP0.x );
|
||||
int sh = sign( aP1.y - aP0.y );
|
||||
|
||||
int radius = std::min( aMaxRadius, std::min( w, h ) );
|
||||
bool use_rounded = aMaxRadius > 0;
|
||||
int dist90 = use_rounded ? KiROUND( ( M_SQRT2 - 1.0 ) * radius ) : 0;
|
||||
int dist45 = use_rounded ? KiROUND( radius * ( 1.0 - M_SQRT1_2 ) ) : 0;
|
||||
|
||||
VECTOR2I mp0, mp1, arc_offset_90, arc_offset_45;
|
||||
|
||||
// we are more horizontal than vertical?
|
||||
// if( m_90deg )
|
||||
// {
|
||||
// if( m_dir == N || m_dir == S )
|
||||
//
|
||||
// }
|
||||
|
||||
if( w > h )
|
||||
{
|
||||
mp0 = VECTOR2I( ( w - h - dist90 ) * sw, 0 ); // direction: E
|
||||
mp1 = VECTOR2I( ( h - dist45 ) * sw, ( h - dist45 ) * sh ); // direction: NE
|
||||
arc_offset_90 = VECTOR2I( 0, radius * sh );
|
||||
arc_offset_45 = VECTOR2I( sw * radius * M_SQRT1_2, -sh * radius * M_SQRT1_2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
mp0 = VECTOR2I( 0, sh * ( h - w - dist90 ) ); // direction: N
|
||||
mp1 = VECTOR2I( sw * ( w - dist45 ), sh * ( w - dist45 ) ); // direction: NE
|
||||
arc_offset_90 = VECTOR2I( radius * sw, 0 );
|
||||
arc_offset_45 = VECTOR2I( -sw * radius * M_SQRT1_2, sh * radius * M_SQRT1_2 );
|
||||
}
|
||||
|
||||
SHAPE_LINE_CHAIN pl;
|
||||
VECTOR2I arc_center;
|
||||
|
||||
pl.Append( aP0 );
|
||||
VECTOR2I next_point;
|
||||
|
||||
if( start_diagonal )
|
||||
{
|
||||
next_point = aP0 + mp1;
|
||||
arc_center = aP0 + mp1 + arc_offset_45;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_point = aP0 + mp0;
|
||||
arc_center = aP0 + mp0 + arc_offset_90;
|
||||
}
|
||||
|
||||
if( use_rounded )
|
||||
{
|
||||
int sa = start_diagonal ? -sw * sh : sw * sh;
|
||||
|
||||
if( h > w )
|
||||
sa = -sa;
|
||||
|
||||
SHAPE_ARC new_arc( arc_center, next_point, sa * 45.0 );
|
||||
pl.Append( new_arc );
|
||||
}
|
||||
else
|
||||
{
|
||||
pl.Append( next_point );
|
||||
}
|
||||
|
||||
pl.Append( aP1 );
|
||||
|
||||
pl.Simplify();
|
||||
return pl;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 CERN
|
||||
* Copyright (C) 2019-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -22,17 +23,18 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#include <assert.h> // for assert
|
||||
#include <math.h> // for cos, sin, M_PI, atan2, ceil
|
||||
#include <type_traits> // for swap
|
||||
#include <algorithm>
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
|
||||
#include <geometry/geometry_utils.h>
|
||||
#include <geometry/seg.h> // for SEG
|
||||
#include <geometry/shape_arc.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
#include <math.h> // for cos, sin, M_PI, atan2, ceil
|
||||
#include <math/box2.h> // for BOX2I
|
||||
#include <math/vector2d.h> // for VECTOR2I, VECTOR2D, VECTOR2
|
||||
#include <type_traits> // for swap
|
||||
|
||||
|
||||
bool SHAPE_ARC::Collide( const SEG& aSeg, int aClearance ) const
|
||||
|
@ -150,16 +152,28 @@ const VECTOR2I SHAPE_ARC::GetP1() const
|
|||
auto ca = m_centralAngle * M_PI / 180.0;
|
||||
VECTOR2I p1;
|
||||
|
||||
p1.x = (int) ( m_pc.x + rvec.x * cos( ca ) - rvec.y * sin( ca ) );
|
||||
p1.y = (int) ( m_pc.y + rvec.x * sin( ca ) + rvec.y * cos( ca ) );
|
||||
p1.x = KiROUND( m_pc.x + rvec.x * cos( ca ) - rvec.y * sin( ca ) );
|
||||
p1.y = KiROUND( m_pc.y + rvec.x * sin( ca ) + rvec.y * cos( ca ) );
|
||||
|
||||
return p1;
|
||||
}
|
||||
|
||||
|
||||
const BOX2I SHAPE_ARC::BBox( int aClearance ) const
|
||||
const VECTOR2I SHAPE_ARC::GetArcMid() const
|
||||
{
|
||||
VECTOR2D rvec = m_p0 - m_pc;
|
||||
auto ca = m_centralAngle / 2.0 * M_PI / 180.0;
|
||||
VECTOR2I p1;
|
||||
|
||||
p1.x = KiROUND( m_pc.x + rvec.x * cos( ca ) - rvec.y * sin( ca ) );
|
||||
p1.y = KiROUND( m_pc.y + rvec.x * sin( ca ) + rvec.y * cos( ca ) );
|
||||
|
||||
return p1;
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_ARC::update_bbox()
|
||||
{
|
||||
BOX2I bbox;
|
||||
std::vector<VECTOR2I> points;
|
||||
// Put start and end points in the point list
|
||||
points.push_back( m_p0 );
|
||||
|
@ -197,7 +211,13 @@ const BOX2I SHAPE_ARC::BBox( int aClearance ) const
|
|||
points.push_back( quad_pt );
|
||||
}
|
||||
|
||||
bbox.Compute( points );
|
||||
m_bbox.Compute( points );
|
||||
}
|
||||
|
||||
|
||||
const BOX2I SHAPE_ARC::BBox( int aClearance ) const
|
||||
{
|
||||
BOX2I bbox( m_bbox );
|
||||
|
||||
if( aClearance != 0 )
|
||||
bbox.Inflate( aClearance );
|
||||
|
@ -208,8 +228,15 @@ const BOX2I SHAPE_ARC::BBox( int aClearance ) const
|
|||
|
||||
bool SHAPE_ARC::Collide( const VECTOR2I& aP, int aClearance ) const
|
||||
{
|
||||
assert( false );
|
||||
int minDist = aClearance + m_width / 2;
|
||||
auto bbox = BBox( minDist );
|
||||
|
||||
if( !bbox.Contains( aP ) )
|
||||
return false;
|
||||
|
||||
auto dist = ( aP - GetCenter() ).SquaredEuclideanNorm();
|
||||
|
||||
return dist <= ( GetRadius() + minDist ) && dist >= ( GetRadius() - minDist );
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -192,7 +192,11 @@ void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const VECTOR2I&
|
|||
{
|
||||
m_points.erase( m_points.begin() + aStartIndex + 1, m_points.begin() + aEndIndex + 1 );
|
||||
m_points[aStartIndex] = aP;
|
||||
|
||||
m_shapes.erase( m_shapes.begin() + aStartIndex + 1, m_shapes.begin() + aEndIndex + 1 );
|
||||
}
|
||||
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,47 +208,26 @@ void SHAPE_LINE_CHAIN::Replace( int aStartIndex, int aEndIndex, const SHAPE_LINE
|
|||
if( aStartIndex < 0 )
|
||||
aStartIndex += PointCount();
|
||||
|
||||
aEndIndex = std::min( aEndIndex, PointCount() - 1 );
|
||||
ssize_t arc_index = -1;
|
||||
Remove( aStartIndex, aEndIndex );
|
||||
|
||||
// N.B. This works because convertArc changes m_shapes on the first run
|
||||
for( int ind = aStartIndex; ind <= aEndIndex; ind++ )
|
||||
{
|
||||
if( m_shapes[ind] != SHAPE_IS_PT )
|
||||
{
|
||||
if( arc_index == -1 )
|
||||
arc_index = m_shapes[ind];
|
||||
// The total new arcs index is added to the new arc indices
|
||||
size_t prev_arc_count = m_arcs.size();
|
||||
auto new_shapes = aLine.m_shapes;
|
||||
|
||||
convertArc( ind );
|
||||
}
|
||||
}
|
||||
for( auto& shape : new_shapes )
|
||||
shape += prev_arc_count;
|
||||
|
||||
for( auto remaining_it = m_shapes.erase( m_shapes.begin() + aStartIndex,
|
||||
m_shapes.begin() + aEndIndex + 1 );
|
||||
remaining_it != m_shapes.end(); remaining_it++ )
|
||||
{
|
||||
if( *remaining_it != SHAPE_IS_PT )
|
||||
*remaining_it += aLine.m_arcs.size();
|
||||
}
|
||||
|
||||
m_shapes.insert( m_shapes.begin() + aStartIndex, aLine.m_shapes.begin(), aLine.m_shapes.end() );
|
||||
|
||||
for( auto new_it = m_shapes.begin() + aStartIndex;
|
||||
new_it != m_shapes.begin() + aStartIndex + aLine.m_shapes.size() + 1; new_it++ )
|
||||
{
|
||||
if( *new_it != SHAPE_IS_PT )
|
||||
*new_it += arc_index;
|
||||
}
|
||||
|
||||
m_arcs.insert( m_arcs.begin() + arc_index, aLine.m_arcs.begin(), aLine.m_arcs.end() );
|
||||
|
||||
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
|
||||
m_shapes.insert( m_shapes.begin() + aStartIndex, new_shapes.begin(), new_shapes.end() );
|
||||
m_points.insert( m_points.begin() + aStartIndex, aLine.m_points.begin(), aLine.m_points.end() );
|
||||
m_arcs.insert( m_arcs.end(), aLine.m_arcs.begin(), aLine.m_arcs.end() );
|
||||
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
|
||||
{
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
if( aEndIndex < 0 )
|
||||
aEndIndex += PointCount();
|
||||
|
||||
|
@ -255,23 +238,21 @@ void SHAPE_LINE_CHAIN::Remove( int aStartIndex, int aEndIndex )
|
|||
return;
|
||||
|
||||
aEndIndex = std::min( aEndIndex, PointCount() );
|
||||
std::vector<size_t> extra_arcs;
|
||||
ssize_t last_arc = -1;
|
||||
std::set<size_t> extra_arcs;
|
||||
|
||||
for( ssize_t i = aStartIndex; i < aEndIndex; i++)
|
||||
// Remove any overlapping arcs in the point range
|
||||
for( int i = aStartIndex; i < aEndIndex; i++ )
|
||||
{
|
||||
if( m_shapes[i] != SHAPE_IS_PT && m_shapes[i] != last_arc )
|
||||
extra_arcs.emplace_back( m_shapes[i] );
|
||||
if( m_shapes[i] != SHAPE_IS_PT )
|
||||
extra_arcs.insert( m_shapes[i] );
|
||||
}
|
||||
|
||||
// Reverse the sort order to ensure we maintain valid indices
|
||||
std::sort( extra_arcs.begin(), extra_arcs.end(), std::greater<size_t>() );
|
||||
|
||||
for( auto arc : extra_arcs )
|
||||
convertArc( arc );
|
||||
|
||||
m_shapes.erase( m_shapes.begin() + aStartIndex, m_shapes.begin() + aEndIndex + 1 );
|
||||
m_points.erase( m_points.begin() + aStartIndex, m_points.begin() + aEndIndex + 1 );
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -358,7 +339,7 @@ const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex )
|
|||
if( aStartIndex < 0 )
|
||||
aStartIndex += PointCount();
|
||||
|
||||
for( int i = aStartIndex; i <= aEndIndex; i++ )
|
||||
for( int i = aStartIndex; i <= aEndIndex && static_cast<size_t>( i ) < m_points.size(); i++ )
|
||||
rv.Append( m_points[i] );
|
||||
|
||||
return rv;
|
||||
|
@ -367,6 +348,8 @@ const SHAPE_LINE_CHAIN SHAPE_LINE_CHAIN::Slice( int aStartIndex, int aEndIndex )
|
|||
|
||||
void SHAPE_LINE_CHAIN::Append( const SHAPE_LINE_CHAIN& aOtherLine )
|
||||
{
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
|
||||
if( aOtherLine.PointCount() == 0 )
|
||||
return;
|
||||
|
||||
|
@ -378,26 +361,41 @@ void SHAPE_LINE_CHAIN::Append( const SHAPE_LINE_CHAIN& aOtherLine )
|
|||
m_bbox.Merge( p );
|
||||
}
|
||||
|
||||
size_t num_arcs = m_arcs.size();
|
||||
m_arcs.insert( m_arcs.end(), aOtherLine.m_arcs.begin(), aOtherLine.m_arcs.end() );
|
||||
|
||||
for( int i = 1; i < aOtherLine.PointCount(); i++ )
|
||||
{
|
||||
const VECTOR2I p = aOtherLine.CPoint( i );
|
||||
m_points.push_back( p );
|
||||
|
||||
ssize_t arcIndex = aOtherLine.ArcIndex( i );
|
||||
|
||||
if( arcIndex != ssize_t( SHAPE_IS_PT ) )
|
||||
m_shapes.push_back( num_arcs + arcIndex );
|
||||
else
|
||||
m_shapes.push_back( ssize_t( SHAPE_IS_PT ) );
|
||||
|
||||
m_bbox.Merge( p );
|
||||
}
|
||||
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
}
|
||||
|
||||
|
||||
void SHAPE_LINE_CHAIN::Append( const SHAPE_ARC& aArc )
|
||||
{
|
||||
auto& chain = aArc.ConvertToPolyline();
|
||||
m_arcs.push_back( aArc );
|
||||
|
||||
for( auto& pt : chain.CPoints() )
|
||||
{
|
||||
m_points.push_back( pt );
|
||||
m_shapes.push_back( m_arcs.size() );
|
||||
}
|
||||
|
||||
m_arcs.push_back( aArc );
|
||||
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -408,6 +406,8 @@ void SHAPE_LINE_CHAIN::Insert( size_t aVertex, const VECTOR2I& aP )
|
|||
|
||||
m_points.insert( m_points.begin() + aVertex, aP );
|
||||
m_shapes.insert( m_shapes.begin() + aVertex, ssize_t( SHAPE_IS_PT ) );
|
||||
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -437,6 +437,7 @@ void SHAPE_LINE_CHAIN::Insert( size_t aVertex, const SHAPE_ARC& aArc )
|
|||
/// Step 3: Add the vector of indices to the shape vector
|
||||
std::vector<size_t> new_points( chain.PointCount(), arc_pos );
|
||||
m_shapes.insert( m_shapes.begin() + aVertex, new_points.begin(), new_points.end() );
|
||||
assert( m_shapes.size() == m_points.size() );
|
||||
}
|
||||
|
||||
|
||||
|
@ -707,6 +708,7 @@ const OPT<SHAPE_LINE_CHAIN::INTERSECTION> SHAPE_LINE_CHAIN::SelfIntersecting() c
|
|||
SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
|
||||
{
|
||||
std::vector<VECTOR2I> pts_unique;
|
||||
std::vector<ssize_t> shapes_unique;
|
||||
|
||||
if( PointCount() < 2 )
|
||||
{
|
||||
|
@ -728,20 +730,22 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
|
|||
{
|
||||
int j = i + 1;
|
||||
|
||||
while( j < np && CPoint( i ) == CPoint( j ) )
|
||||
while( j < np && m_points[i] == m_points[j] && m_shapes[i] == m_shapes[j] )
|
||||
j++;
|
||||
|
||||
pts_unique.push_back( CPoint( i ) );
|
||||
shapes_unique.push_back( m_shapes[i] );
|
||||
|
||||
i = j;
|
||||
}
|
||||
|
||||
m_points.clear();
|
||||
m_shapes.clear();
|
||||
np = pts_unique.size();
|
||||
|
||||
i = 0;
|
||||
|
||||
// stage 1: eliminate collinear segments
|
||||
// TODO(sh): handle arcs Maybe segment-wise?
|
||||
while( i < np - 2 )
|
||||
{
|
||||
const VECTOR2I p0 = pts_unique[i];
|
||||
|
@ -754,7 +758,7 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
|
|||
n++;
|
||||
|
||||
m_points.push_back( p0 );
|
||||
m_shapes.push_back( ssize_t( SHAPE_IS_PT ) );
|
||||
m_shapes.push_back( shapes_unique[i] );
|
||||
|
||||
if( n > i )
|
||||
i = n;
|
||||
|
@ -762,7 +766,7 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
|
|||
if( n == np )
|
||||
{
|
||||
m_points.push_back( pts_unique[n - 1] );
|
||||
m_shapes.push_back( ssize_t( SHAPE_IS_PT ) );
|
||||
m_shapes.push_back( shapes_unique[n - 1] );
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -772,11 +776,13 @@ SHAPE_LINE_CHAIN& SHAPE_LINE_CHAIN::Simplify()
|
|||
if( np > 1 )
|
||||
{
|
||||
m_points.push_back( pts_unique[np - 2] );
|
||||
m_shapes.push_back( ssize_t( SHAPE_IS_PT ) );
|
||||
m_shapes.push_back( shapes_unique[np - 2] );
|
||||
}
|
||||
|
||||
m_points.push_back( pts_unique[np - 1] );
|
||||
m_shapes.push_back( ssize_t( SHAPE_IS_PT ) );
|
||||
m_shapes.push_back( shapes_unique[np - 1] );
|
||||
|
||||
assert( m_points.size() == m_shapes.size() );
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,7 @@ void BOARD_COMMIT::Push( const wxString& aMessage, bool aCreateUndoEntry, bool a
|
|||
case PCB_LINE_T: // a segment not on copper layers
|
||||
case PCB_TEXT_T: // a text on a layer
|
||||
case PCB_TRACE_T: // a track segment (segment on a copper layer)
|
||||
case PCB_ARC_T: // an arced track segment (segment on a copper layer)
|
||||
case PCB_VIA_T: // a via (like track segment on a copper layer)
|
||||
case PCB_DIMENSION_T: // a dimension (graphic item)
|
||||
case PCB_TARGET_T: // a target (graphic item)
|
||||
|
|
|
@ -58,6 +58,7 @@ public:
|
|||
{
|
||||
case PCB_PAD_T:
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
case PCB_ZONE_AREA_T:
|
||||
return true;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <fctsys.h>
|
||||
#include <common.h>
|
||||
#include <class_board.h>
|
||||
#include <class_track.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
#include <kiface_i.h>
|
||||
#include <pcbnew.h>
|
||||
|
|
|
@ -203,6 +203,7 @@ void BOARD::Move( const wxPoint& aMoveVector ) // overload
|
|||
PCB_TARGET_T,
|
||||
PCB_VIA_T,
|
||||
PCB_TRACE_T,
|
||||
PCB_ARC_T,
|
||||
// PCB_PAD_T, Can't be at board level
|
||||
// PCB_MODULE_TEXT_T, Can't be at board level
|
||||
PCB_MODULE_T,
|
||||
|
@ -549,6 +550,7 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, ADD_MODE aMode )
|
|||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_VIA_T:
|
||||
case PCB_ARC_T:
|
||||
|
||||
// N.B. This inserts a small memory leak as we lose the
|
||||
if( !IsCopperLayer( aBoardItem->GetLayer() ) )
|
||||
|
@ -647,6 +649,7 @@ void BOARD::Remove( BOARD_ITEM* aBoardItem )
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
m_tracks.erase( std::remove_if( m_tracks.begin(), m_tracks.end(),
|
||||
[aBoardItem]( BOARD_ITEM* aItem ) { return aItem == aBoardItem; } ) );
|
||||
|
@ -954,6 +957,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s
|
|||
// consuming) search is made, but this case is statistically rare.
|
||||
case PCB_VIA_T:
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
result = IterateForward( m_Track, inspector, testData, p );
|
||||
|
||||
// skip over any types handled in the above call.
|
||||
|
@ -963,6 +967,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s
|
|||
{
|
||||
case PCB_VIA_T:
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
continue;
|
||||
|
||||
default:
|
||||
|
@ -981,6 +986,7 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR inspector, void* testData, const KICAD_T s
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
result = IterateForward<TRACK*>( m_tracks, inspector, testData, p );
|
||||
++p;
|
||||
break;
|
||||
|
@ -1415,7 +1421,7 @@ std::tuple<int, double, double> BOARD::GetTrackLength( const TRACK& aTrack ) con
|
|||
double length = 0.0;
|
||||
double package_length = 0.0;
|
||||
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_PAD_T, EOT };
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, EOT };
|
||||
auto connectivity = GetBoard()->GetConnectivity();
|
||||
|
||||
for( auto item : connectivity->GetConnectedItems(
|
||||
|
|
|
@ -58,6 +58,9 @@ class SHAPE_POLY_SET;
|
|||
class CONNECTIVITY_DATA;
|
||||
class COMPONENT;
|
||||
|
||||
// Forward declare endpoint from class_track.h
|
||||
enum ENDPOINT_T : int;
|
||||
|
||||
/**
|
||||
* Enum LAYER_T
|
||||
* gives the allowed types of layers, same as Specctra DSN spec.
|
||||
|
|
|
@ -1449,6 +1449,7 @@ double MODULE::CoverageRatio( const GENERAL_COLLECTOR& aCollector ) const
|
|||
case PCB_TEXT_T:
|
||||
case PCB_MODULE_TEXT_T:
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
addRect( holes, item->GetBoundingBox() );
|
||||
break;
|
||||
|
|
|
@ -977,16 +977,28 @@ bool TRACK::HitTest( const wxPoint& aPosition, int aAccuracy ) const
|
|||
bool ARC::HitTest( const wxPoint& aPosition, int aAccuracy ) const
|
||||
{
|
||||
int max_dist = aAccuracy + ( m_Width / 2 );
|
||||
wxPoint center = GetPosition();
|
||||
wxPoint relpos = aPosition - center;
|
||||
double dist = EuclideanNorm( relpos );
|
||||
double radius = GetRadius();
|
||||
|
||||
auto rel_start = EuclideanNorm( aPosition - m_Start );
|
||||
auto rel_mid = EuclideanNorm( aPosition - m_Mid );
|
||||
auto rel_end = EuclideanNorm( aPosition - m_End );
|
||||
|
||||
if( rel_start <= max_dist || rel_mid <= max_dist || rel_end <= max_dist )
|
||||
return true;
|
||||
|
||||
//TODO: Calculate along arc
|
||||
if( std::abs( dist - radius ) > max_dist )
|
||||
return false;
|
||||
|
||||
double arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg, in 0.1 deg
|
||||
double arc_hittest = ArcTangente( relpos.y, relpos.x );
|
||||
|
||||
// Calculate relative angle between the starting point of the arc, and the test point
|
||||
arc_hittest -= arc_angle_start;
|
||||
|
||||
// Normalise arc_hittest between 0 ... 360 deg
|
||||
NORMALIZE_ANGLE_POS( arc_hittest );
|
||||
double arc_angle = GetAngle();
|
||||
|
||||
if( arc_angle < 0 )
|
||||
return arc_hittest >= 3600 + arc_angle;
|
||||
|
||||
return arc_hittest <= GetAngle();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1090,6 +1102,50 @@ void VIA::SwapData( BOARD_ITEM* aImage )
|
|||
std::swap( *((VIA*) this), *((VIA*) aImage) );
|
||||
}
|
||||
|
||||
|
||||
const wxPoint ARC::GetPosition() const
|
||||
{
|
||||
auto center = GetArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ) );
|
||||
return wxPoint( center.x, center.y );
|
||||
}
|
||||
|
||||
double ARC::GetRadius() const
|
||||
{
|
||||
auto center = GetArcCenter( VECTOR2I( m_Start ), VECTOR2I( m_Mid ), VECTOR2I( m_End ) );
|
||||
return GetLineLength( wxPoint( center ), m_Start );
|
||||
}
|
||||
|
||||
double ARC::GetAngle() const
|
||||
{
|
||||
wxPoint center = GetPosition();
|
||||
wxPoint p0 = m_Start - center;
|
||||
wxPoint p1 = m_Mid - center;
|
||||
wxPoint p2 = m_End - center;
|
||||
double angle1 = ArcTangente( p1.y, p1.x ) - ArcTangente( p0.y, p0.x );
|
||||
double angle2 = ArcTangente( p2.y, p2.x ) - ArcTangente( p1.y, p1.x );
|
||||
|
||||
return NormalizeAngle180( angle1 ) + NormalizeAngle180( angle2 );
|
||||
}
|
||||
|
||||
double ARC::GetArcAngleStart() const
|
||||
{
|
||||
wxPoint center = GetPosition();
|
||||
|
||||
double angleStart = ArcTangente( m_Start.y - center.y,
|
||||
m_Start.x - center.x );
|
||||
return NormalizeAnglePos( angleStart );
|
||||
}
|
||||
|
||||
double ARC::GetArcAngleEnd() const
|
||||
{
|
||||
wxPoint center = GetPosition();
|
||||
|
||||
double angleEnd = ArcTangente( m_End.y - center.y,
|
||||
m_End.x - center.x );
|
||||
return NormalizeAnglePos( angleEnd );
|
||||
}
|
||||
|
||||
|
||||
#if defined(DEBUG)
|
||||
|
||||
wxString TRACK::ShowState( int stateBits )
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2004 Jean-Pierre Charras, jaen-pierre.charras@gipsa-lab.inpg.com
|
||||
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -38,6 +38,7 @@
|
|||
#include <pcbnew.h>
|
||||
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_arc.h>
|
||||
|
||||
#include <trigo.h>
|
||||
|
||||
|
@ -50,14 +51,15 @@ class SHAPE_POLY_SET;
|
|||
|
||||
|
||||
// Flag used in locate routines (from which endpoint work)
|
||||
enum ENDPOINT_T {
|
||||
enum ENDPOINT_T : int
|
||||
{
|
||||
ENDPOINT_START = 0,
|
||||
ENDPOINT_END = 1
|
||||
};
|
||||
|
||||
// Via types
|
||||
// Note that this enum must be synchronized to GAL_LAYER_ID
|
||||
enum class VIATYPE
|
||||
enum class VIATYPE : int
|
||||
{
|
||||
THROUGH = 3, /* Always a through hole via */
|
||||
BLIND_BURIED = 2, /* this via can be on internal layers */
|
||||
|
@ -262,6 +264,14 @@ class ARC : public TRACK
|
|||
public:
|
||||
ARC( BOARD_ITEM* aParent ) : TRACK( aParent, PCB_ARC_T ){};
|
||||
|
||||
ARC( BOARD_ITEM* aParent, const SHAPE_ARC* aArc ) :
|
||||
TRACK( aParent, PCB_ARC_T )
|
||||
{
|
||||
m_Start = wxPoint( aArc->GetP0() );
|
||||
m_End = wxPoint( aArc->GetP1() );
|
||||
m_Mid = wxPoint( aArc->GetArcMid() );
|
||||
}
|
||||
|
||||
static inline bool ClassOf( const EDA_ITEM *aItem )
|
||||
{
|
||||
return aItem && PCB_ARC_T == aItem->Type();
|
||||
|
@ -281,6 +291,19 @@ public:
|
|||
void SetMid( const wxPoint& aMid ) { m_Mid = aMid; }
|
||||
const wxPoint& GetMid() const { return m_Mid; }
|
||||
|
||||
void SetPosition( const wxPoint& aPos ) override
|
||||
{
|
||||
printf("Setting the arc position\n");
|
||||
m_Start = aPos;
|
||||
}
|
||||
|
||||
virtual const wxPoint GetPosition() const override;
|
||||
|
||||
double GetRadius() const;
|
||||
double GetAngle() const;
|
||||
double GetArcAngleStart() const;
|
||||
double GetArcAngleEnd() const;
|
||||
|
||||
virtual bool HitTest( const wxPoint& aPosition, int aAccuracy = 0 ) const override;
|
||||
|
||||
virtual bool HitTest( const EDA_RECT& aRect, bool aContained = true, int aAccuracy = 0 ) const override;
|
||||
|
@ -294,7 +317,7 @@ public:
|
|||
|
||||
/**
|
||||
* Function GetLength
|
||||
* returns the length of the track using the hypotenuse calculation.
|
||||
* returns the length of the arc track using a series of segment approximations.
|
||||
* @return double - the length of the track
|
||||
*/
|
||||
virtual double GetLength() const override
|
||||
|
|
|
@ -51,6 +51,7 @@ const KICAD_T GENERAL_COLLECTOR::AllBoardItems[] = {
|
|||
PCB_TARGET_T, // in m_Drawings
|
||||
PCB_VIA_T, // in m_Tracks
|
||||
PCB_TRACE_T, // in m_Tracks
|
||||
PCB_ARC_T, // in m_Tracks
|
||||
PCB_PAD_T, // in modules
|
||||
PCB_MODULE_TEXT_T, // in modules
|
||||
PCB_MODULE_T, // in m_Modules
|
||||
|
@ -66,6 +67,7 @@ const KICAD_T GENERAL_COLLECTOR::BoardLevelItems[] = {
|
|||
PCB_DIMENSION_T,
|
||||
PCB_TARGET_T,
|
||||
PCB_VIA_T,
|
||||
PCB_ARC_T,
|
||||
PCB_TRACE_T,
|
||||
PCB_MODULE_T,
|
||||
PCB_ZONE_AREA_T,
|
||||
|
@ -81,6 +83,7 @@ const KICAD_T GENERAL_COLLECTOR::AllButZones[] = {
|
|||
PCB_TARGET_T,
|
||||
PCB_VIA_T,
|
||||
PCB_TRACE_T,
|
||||
PCB_ARC_T,
|
||||
PCB_PAD_T,
|
||||
PCB_MODULE_TEXT_T,
|
||||
PCB_MODULE_T,
|
||||
|
@ -106,6 +109,7 @@ const KICAD_T GENERAL_COLLECTOR::PadsOrTracks[] = {
|
|||
PCB_PAD_T,
|
||||
PCB_VIA_T,
|
||||
PCB_TRACE_T,
|
||||
PCB_ARC_T,
|
||||
EOT
|
||||
};
|
||||
|
||||
|
@ -131,6 +135,7 @@ const KICAD_T GENERAL_COLLECTOR::ModuleItems[] = {
|
|||
|
||||
const KICAD_T GENERAL_COLLECTOR::Tracks[] = {
|
||||
PCB_TRACE_T,
|
||||
PCB_ARC_T,
|
||||
PCB_VIA_T,
|
||||
EOT
|
||||
};
|
||||
|
@ -139,6 +144,7 @@ const KICAD_T GENERAL_COLLECTOR::Tracks[] = {
|
|||
const KICAD_T GENERAL_COLLECTOR::LockableItems[] = {
|
||||
PCB_MODULE_T,
|
||||
PCB_TRACE_T,
|
||||
PCB_ARC_T,
|
||||
PCB_VIA_T,
|
||||
EOT
|
||||
};
|
||||
|
@ -184,6 +190,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
breakhere++;
|
||||
break;
|
||||
|
||||
|
@ -263,6 +270,7 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_ITEM* testItem, void* testData )
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
if( m_Guide->IgnoreTracks() )
|
||||
goto exit;
|
||||
break;
|
||||
|
|
|
@ -60,6 +60,7 @@ bool CN_CONNECTIVITY_ALGO::Remove( BOARD_ITEM* aItem )
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
m_itemMap[ static_cast<BOARD_CONNECTED_ITEM*>( aItem ) ].MarkItemsAsInvalid();
|
||||
m_itemMap.erase( static_cast<BOARD_CONNECTED_ITEM*>( aItem ) );
|
||||
m_itemList.SetDirty( true );
|
||||
|
@ -153,6 +154,16 @@ bool CN_CONNECTIVITY_ALGO::Add( BOARD_ITEM* aItem )
|
|||
break;
|
||||
}
|
||||
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
if( m_itemMap.find( static_cast<ARC*>( aItem ) ) != m_itemMap.end() )
|
||||
return false;
|
||||
|
||||
add( m_itemList, static_cast<ARC*>( aItem ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case PCB_VIA_T:
|
||||
if( m_itemMap.find( static_cast<VIA*>( aItem ) ) != m_itemMap.end() )
|
||||
return false;
|
||||
|
@ -280,8 +291,10 @@ void CN_CONNECTIVITY_ALGO::searchConnections()
|
|||
|
||||
const CN_CONNECTIVITY_ALGO::CLUSTERS CN_CONNECTIVITY_ALGO::SearchClusters( CLUSTER_SEARCH_MODE aMode )
|
||||
{
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_PAD_T, PCB_VIA_T, PCB_ZONE_AREA_T, PCB_MODULE_T, EOT };
|
||||
constexpr KICAD_T no_zones[] = { PCB_TRACE_T, PCB_PAD_T, PCB_VIA_T, PCB_MODULE_T, EOT };
|
||||
constexpr KICAD_T types[] =
|
||||
{ PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T, PCB_VIA_T, PCB_ZONE_AREA_T, PCB_MODULE_T, EOT };
|
||||
constexpr KICAD_T no_zones[] =
|
||||
{ PCB_TRACE_T, PCB_ARC_T, PCB_PAD_T, PCB_VIA_T, PCB_MODULE_T, EOT };
|
||||
|
||||
if( aMode == CSM_PROPAGATE )
|
||||
return SearchClusters( aMode, no_zones, -1 );
|
||||
|
@ -423,6 +436,7 @@ void CN_CONNECTIVITY_ALGO::Build( const std::vector<BOARD_ITEM*>& aItems )
|
|||
switch( item->Type() )
|
||||
{
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
case PCB_PAD_T:
|
||||
Add( item );
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KICAD, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2017 CERN
|
||||
* Copyright (C) 2018-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2018-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@ -248,8 +248,8 @@ void CONNECTIVITY_DATA::ComputeDynamicRatsnest( const std::vector<BOARD_ITEM*>&
|
|||
|
||||
if( std::none_of( aItems.begin(), aItems.end(), []( const BOARD_ITEM* aItem )
|
||||
{ return( aItem->Type() == PCB_TRACE_T || aItem->Type() == PCB_PAD_T ||
|
||||
aItem->Type() == PCB_ZONE_AREA_T || aItem->Type() == PCB_MODULE_T ||
|
||||
aItem->Type() == PCB_VIA_T ); } ) )
|
||||
aItem->Type() == PCB_ARC_T || aItem->Type() == PCB_ZONE_AREA_T ||
|
||||
aItem->Type() == PCB_MODULE_T || aItem->Type() == PCB_VIA_T ); } ) )
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
@ -448,7 +448,10 @@ const
|
|||
{
|
||||
for( auto connected : citem->ConnectedItems() )
|
||||
{
|
||||
if( connected->Valid() && ( connected->Parent()->Type() == PCB_TRACE_T || connected->Parent()->Type() == PCB_VIA_T ) )
|
||||
if( connected->Valid() &&
|
||||
( connected->Parent()->Type() == PCB_TRACE_T ||
|
||||
connected->Parent()->Type() == PCB_VIA_T ||
|
||||
connected->Parent()->Type() == PCB_ARC_T ) )
|
||||
tracks.insert( static_cast<TRACK*> ( connected->Parent() ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@ int CN_ITEM::AnchorCount() const
|
|||
case PCB_PAD_T:
|
||||
return 5; // center, north, south, east and west
|
||||
case PCB_TRACE_T:
|
||||
return 2; // stard and end
|
||||
case PCB_ARC_T:
|
||||
return 2; // start and end
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
@ -125,6 +126,7 @@ const VECTOR2I CN_ITEM::GetAnchor( int n ) const
|
|||
break;
|
||||
}
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
if( n == 0 )
|
||||
return static_cast<const TRACK*>( m_parent )->GetStart();
|
||||
else
|
||||
|
@ -236,8 +238,8 @@ CN_ITEM* CN_LIST::Add( D_PAD* pad )
|
|||
return item;
|
||||
}
|
||||
|
||||
CN_ITEM* CN_LIST::Add( TRACK* track )
|
||||
{
|
||||
CN_ITEM* CN_LIST::Add( TRACK* track )
|
||||
{
|
||||
auto item = new CN_ITEM( track, true );
|
||||
m_items.push_back( item );
|
||||
item->AddAnchor( track->GetStart() );
|
||||
|
@ -246,7 +248,19 @@ CN_ITEM* CN_LIST::Add( D_PAD* pad )
|
|||
addItemtoTree( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
CN_ITEM* CN_LIST::Add( ARC* aArc )
|
||||
{
|
||||
auto item = new CN_ITEM( aArc, true );
|
||||
m_items.push_back( item );
|
||||
item->AddAnchor( aArc->GetStart() );
|
||||
item->AddAnchor( aArc->GetEnd() );
|
||||
item->SetLayer( aArc->GetLayer() );
|
||||
addItemtoTree( item );
|
||||
SetDirty();
|
||||
return item;
|
||||
}
|
||||
|
||||
CN_ITEM* CN_LIST::Add( VIA* via )
|
||||
{
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <class_board.h>
|
||||
#include <class_pad.h>
|
||||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <class_zone.h>
|
||||
|
||||
#include <geometry/shape_poly_set.h>
|
||||
|
@ -476,6 +477,8 @@ public:
|
|||
|
||||
CN_ITEM* Add( TRACK* track );
|
||||
|
||||
CN_ITEM* Add( ARC* track );
|
||||
|
||||
CN_ITEM* Add( VIA* via );
|
||||
|
||||
const std::vector<CN_ITEM*> Add( ZONE_CONTAINER* zone );
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <confirm.h>
|
||||
#include <pcb_edit_frame.h>
|
||||
#include <class_board.h>
|
||||
#include <class_track.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
#include <view/view.h>
|
||||
#include <pcb_layer_box_selector.h>
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include <pcbnew.h>
|
||||
#include <tools/pcb_inspection_tool.h>
|
||||
#include <class_board.h>
|
||||
#include <class_track.h>
|
||||
#include <dialog_select_net_from_list_base.h>
|
||||
#include <eda_pattern_match.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
|
|
|
@ -93,6 +93,7 @@ DIALOG_TRACK_VIA_PROPERTIES::DIALOG_TRACK_VIA_PROPERTIES( PCB_BASE_FRAME* aParen
|
|||
switch( item->Type() )
|
||||
{
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
const TRACK* t = static_cast<const TRACK*>( item );
|
||||
|
||||
|
@ -410,6 +411,7 @@ bool DIALOG_TRACK_VIA_PROPERTIES::TransferDataFromWindow()
|
|||
switch( item->Type() )
|
||||
{
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
wxASSERT( m_tracks );
|
||||
TRACK* t = static_cast<TRACK*>( item );
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <collectors.h>
|
||||
#include <reporter.h>
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <build_version.h>
|
||||
|
||||
#include <class_board.h>
|
||||
#include <class_track.h>
|
||||
|
||||
#include <pcbplot.h>
|
||||
#include <pcbnew.h>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2018 Jean_Pierre Charras <jp.charras at wanadoo.fr>
|
||||
* Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <class_zone.h>
|
||||
|
||||
#include <board_stackup_manager/stackup_predefined_prms.h>
|
||||
|
|
|
@ -442,6 +442,7 @@ void PCB_IO::Format( BOARD_ITEM* aItem, int aNestLevel ) const
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
format( static_cast<TRACK*>( aItem ), aNestLevel );
|
||||
break;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2012 CERN.
|
||||
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
|
|
|
@ -348,6 +348,10 @@ bool PCB_PAINTER::Draw( const VIEW_ITEM* aItem, int aLayer )
|
|||
draw( static_cast<const TRACK*>( item ), aLayer );
|
||||
break;
|
||||
|
||||
case PCB_ARC_T:
|
||||
draw( static_cast<const ARC*>( item ), aLayer );
|
||||
break;
|
||||
|
||||
case PCB_VIA_T:
|
||||
draw( static_cast<const VIA*>( item ), aLayer );
|
||||
break;
|
||||
|
@ -475,6 +479,45 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
|
|||
}
|
||||
|
||||
|
||||
void PCB_PAINTER::draw( const ARC* aArc, int aLayer )
|
||||
{
|
||||
VECTOR2D center( aArc->GetCenter() );
|
||||
int width = aArc->GetWidth();
|
||||
|
||||
if( IsCopperLayer( aLayer ) )
|
||||
{
|
||||
// Draw a regular track
|
||||
const COLOR4D& color = m_pcbSettings.GetColor( aArc, aLayer );
|
||||
bool outline_mode = m_pcbSettings.m_sketchMode[LAYER_TRACKS];
|
||||
m_gal->SetStrokeColor( color );
|
||||
m_gal->SetFillColor( color );
|
||||
m_gal->SetIsStroke( outline_mode );
|
||||
m_gal->SetIsFill( not outline_mode );
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
|
||||
auto radius = aArc->GetRadius();
|
||||
auto start_angle = DECIDEG2RAD( aArc->GetArcAngleStart() );
|
||||
auto angle = DECIDEG2RAD( aArc->GetAngle() );
|
||||
|
||||
m_gal->DrawArcSegment( center, radius, start_angle, start_angle + angle, width );
|
||||
|
||||
// Clearance lines
|
||||
constexpr int clearanceFlags = PCB_RENDER_SETTINGS::CL_EXISTING | PCB_RENDER_SETTINGS::CL_TRACKS;
|
||||
|
||||
if( ( m_pcbSettings.m_clearance & clearanceFlags ) == clearanceFlags )
|
||||
{
|
||||
m_gal->SetLineWidth( m_pcbSettings.m_outlineWidth );
|
||||
m_gal->SetIsFill( false );
|
||||
m_gal->SetIsStroke( true );
|
||||
m_gal->SetStrokeColor( color );
|
||||
|
||||
m_gal->DrawArcSegment( center, radius, start_angle, start_angle + angle,
|
||||
width + aArc->GetClearance() * 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PCB_PAINTER::draw( const VIA* aVia, int aLayer )
|
||||
{
|
||||
VECTOR2D center( aVia->GetStart() );
|
||||
|
|
|
@ -37,6 +37,7 @@ class COLORS_DESIGN_SETTINGS;
|
|||
class PCB_DISPLAY_OPTIONS;
|
||||
|
||||
class BOARD_ITEM;
|
||||
class ARC;
|
||||
class BOARD;
|
||||
class VIA;
|
||||
class TRACK;
|
||||
|
@ -247,6 +248,7 @@ protected:
|
|||
|
||||
// Drawing functions for various types of PCB-specific items
|
||||
void draw( const TRACK* aTrack, int aLayer );
|
||||
void draw( const ARC* aArc, int aLayer );
|
||||
void draw( const VIA* aVia, int aLayer );
|
||||
void draw( const D_PAD* aPad, int aLayer );
|
||||
void draw( const DRAWSEGMENT* aSegment, int aLayer );
|
||||
|
|
|
@ -587,7 +587,7 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
|
|||
break;
|
||||
|
||||
case T_arc:
|
||||
m_board->Add( parseARC(), ADD_INSERT );
|
||||
m_board->Add( parseARC(), ADD_MODE::INSERT );
|
||||
break;
|
||||
|
||||
case T_via:
|
||||
|
@ -3406,7 +3406,7 @@ ARC* PCB_PARSER::parseARC()
|
|||
break;
|
||||
|
||||
case T_tstamp:
|
||||
arc->SetTimeStamp( parseHex() );
|
||||
const_cast<KIID&>( arc->m_Uuid ) = KIID( CurStr() );
|
||||
break;
|
||||
|
||||
case T_status:
|
||||
|
|
|
@ -13,6 +13,7 @@ set( PCBNEW_PNS_SRCS
|
|||
time_limit.cpp
|
||||
pns_kicad_iface.cpp
|
||||
pns_algo_base.cpp
|
||||
pns_arc.cpp
|
||||
pns_diff_pair.cpp
|
||||
pns_diff_pair_placer.cpp
|
||||
pns_dp_meander_placer.cpp
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Author: Seth Hillbrand <hillbrand@ucdavis.edu>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_node.h"
|
||||
#include "pns_router.h"
|
||||
#include "pns_utils.h"
|
||||
#include "pns_via.h"
|
||||
|
||||
#include <geometry/shape_rect.h>
|
||||
|
||||
namespace PNS {
|
||||
|
||||
|
||||
const SHAPE_LINE_CHAIN ARC::Hull( int aClearance, int aWalkaroundThickness ) const
|
||||
{
|
||||
return ArcHull( m_arc, aClearance, aWalkaroundThickness );
|
||||
}
|
||||
|
||||
|
||||
ARC* ARC::Clone() const
|
||||
{
|
||||
ARC* a = new ARC( m_arc, m_net );
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
OPT_BOX2I ARC::ChangedArea( const ARC* aOther ) const
|
||||
{
|
||||
BOX2I tmp = Shape()->BBox();
|
||||
tmp.Merge( aOther->Shape()->BBox() );
|
||||
return tmp;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Author: Seth Hillbrand <hillbrand@ucdavis.edu>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PNS_ARC_H
|
||||
#define __PNS_ARC_H
|
||||
|
||||
#include <math/vector2d.h>
|
||||
|
||||
#include <geometry/shape_arc.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
#include "pns_line.h"
|
||||
#include "pns_linked_item.h"
|
||||
|
||||
namespace PNS {
|
||||
|
||||
class NODE;
|
||||
|
||||
class ARC : public LINKED_ITEM
|
||||
{
|
||||
public:
|
||||
ARC() : LINKED_ITEM( ARC_T )
|
||||
{}
|
||||
|
||||
ARC( const SHAPE_ARC& aArc, int aNet ) : LINKED_ITEM( ARC_T ), m_arc( aArc )
|
||||
{
|
||||
m_net = aNet;
|
||||
}
|
||||
|
||||
ARC( const ARC& aParentArc, const SHAPE_ARC& aArc )
|
||||
: LINKED_ITEM( ARC_T ),
|
||||
m_arc( aArc )
|
||||
{
|
||||
m_net = aParentArc.Net();
|
||||
m_layers = aParentArc.Layers();
|
||||
m_marker = aParentArc.Marker();
|
||||
m_rank = aParentArc.Rank();
|
||||
}
|
||||
|
||||
ARC( const LINE& aParentLine, const SHAPE_ARC& aArc ) :
|
||||
LINKED_ITEM( ARC_T ),
|
||||
m_arc( aArc.GetCenter(), aArc.GetP0(), aArc.GetCentralAngle(), aParentLine.Width() )
|
||||
{
|
||||
m_net = aParentLine.Net();
|
||||
m_layers = aParentLine.Layers();
|
||||
m_marker = aParentLine.Marker();
|
||||
m_rank = aParentLine.Rank();
|
||||
}
|
||||
|
||||
static inline bool ClassOf( const ITEM* aItem )
|
||||
{
|
||||
return aItem && ARC_T == aItem->Kind();
|
||||
}
|
||||
|
||||
ARC* Clone() const override;
|
||||
|
||||
const SHAPE* Shape() const override
|
||||
{
|
||||
return static_cast<const SHAPE*>( &m_arc );
|
||||
}
|
||||
|
||||
void SetWidth( int aWidth ) override
|
||||
{
|
||||
m_arc.SetWidth(aWidth);
|
||||
}
|
||||
|
||||
int Width() const override
|
||||
{
|
||||
return m_arc.GetWidth();
|
||||
}
|
||||
|
||||
const SHAPE_LINE_CHAIN CLine() const
|
||||
{
|
||||
return SHAPE_LINE_CHAIN( m_arc );
|
||||
}
|
||||
|
||||
const SHAPE_LINE_CHAIN Hull( int aClearance, int aWalkaroundThickness ) const override;
|
||||
|
||||
virtual VECTOR2I Anchor( int n ) const override
|
||||
{
|
||||
if( n == 0 )
|
||||
return m_arc.GetP0();
|
||||
else
|
||||
return m_arc.GetP1();
|
||||
}
|
||||
|
||||
virtual int AnchorCount() const override
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
OPT_BOX2I ChangedArea( const ARC* aOther ) const;
|
||||
|
||||
private:
|
||||
SHAPE_ARC m_arc;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -111,17 +111,15 @@ bool DP_PRIMITIVE_PAIR::Directional() const
|
|||
}
|
||||
|
||||
|
||||
DIRECTION_45 DP_PRIMITIVE_PAIR::anchorDirection( ITEM* aItem, const VECTOR2I& aP ) const
|
||||
DIRECTION_45 DP_PRIMITIVE_PAIR::anchorDirection( const ITEM* aItem, const VECTOR2I& aP ) const
|
||||
{
|
||||
if( !aItem->OfKind ( ITEM::SEGMENT_T ) )
|
||||
if( !aItem->OfKind ( ITEM::SEGMENT_T | ITEM::ARC_T ) )
|
||||
return DIRECTION_45();
|
||||
|
||||
SEGMENT* s = static_cast<SEGMENT*>( aItem );
|
||||
|
||||
if( s->Seg().A == aP )
|
||||
return DIRECTION_45( s->Seg().A - s->Seg().B );
|
||||
if( aItem->Anchor( 0 ) == aP )
|
||||
return DIRECTION_45( aItem->Anchor( 0 ) - aItem->Anchor( 1 ) );
|
||||
else
|
||||
return DIRECTION_45( s->Seg().B - s->Seg().A );
|
||||
return DIRECTION_45( aItem->Anchor( 1 ) - aItem->Anchor( 0 ) );
|
||||
}
|
||||
|
||||
void DP_PRIMITIVE_PAIR::CursorOrientation( const VECTOR2I& aCursorPos, VECTOR2I& aMidpoint, VECTOR2I& aDirection ) const
|
||||
|
|
|
@ -170,7 +170,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
DIRECTION_45 anchorDirection( ITEM* aItem, const VECTOR2I& aP ) const;
|
||||
DIRECTION_45 anchorDirection( const ITEM* aItem, const VECTOR2I& aP ) const;
|
||||
|
||||
ITEM* m_primP;
|
||||
ITEM* m_primN;
|
||||
|
|
|
@ -411,16 +411,17 @@ OPT_VECTOR2I DIFF_PAIR_PLACER::getDanglingAnchor( NODE* aNode, ITEM* aItem )
|
|||
case ITEM::SOLID_T:
|
||||
return aItem->Anchor( 0 );
|
||||
|
||||
case ITEM::ARC_T:
|
||||
case ITEM::SEGMENT_T:
|
||||
{
|
||||
SEGMENT* s =static_cast<SEGMENT*>( aItem );
|
||||
SEGMENT* s = static_cast<SEGMENT*>( aItem );
|
||||
|
||||
JOINT* jA = aNode->FindJoint( s->Seg().A, s );
|
||||
JOINT* jB = aNode->FindJoint( s->Seg().B, s );
|
||||
JOINT* jA = aNode->FindJoint( aItem->Anchor( 0 ), aItem );
|
||||
JOINT* jB = aNode->FindJoint( aItem->Anchor( 1 ), aItem );
|
||||
|
||||
if( jA->LinkCount() == 1 )
|
||||
if( jA && jA->LinkCount() == 1 )
|
||||
return s->Seg().A;
|
||||
else if( jB->LinkCount() == 1 )
|
||||
else if( jB && jB->LinkCount() == 1 )
|
||||
return s->Seg().B;
|
||||
else
|
||||
return OPT_VECTOR2I();
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||
*
|
||||
* Copyright (C) 2013-2014 CERN
|
||||
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2019 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
|
@ -19,6 +19,8 @@
|
|||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pns_arc.h"
|
||||
|
||||
#include "pns_dragger.h"
|
||||
#include "pns_shove.h"
|
||||
#include "pns_router.h"
|
||||
|
@ -69,6 +71,7 @@ bool DRAGGER::startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg )
|
|||
}
|
||||
else if( distB <= w2 )
|
||||
{
|
||||
//todo (snh) Adjust segment for arcs
|
||||
m_draggedSegmentIndex++;
|
||||
m_mode = DM_CORNER;
|
||||
}
|
||||
|
@ -89,6 +92,17 @@ bool DRAGGER::startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg )
|
|||
}
|
||||
|
||||
|
||||
|
||||
bool DRAGGER::startDragArc( const VECTOR2D& aP, ARC* aArc )
|
||||
{
|
||||
m_draggedLine = m_world->AssembleLine( aArc, &m_draggedSegmentIndex );
|
||||
m_shove->SetInitialLine( m_draggedLine );
|
||||
m_mode = DM_ARC;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool DRAGGER::startDragVia( VIA* aVia )
|
||||
{
|
||||
m_initialVia = aVia->MakeHandle();
|
||||
|
@ -110,10 +124,10 @@ const ITEM_SET DRAGGER::findViaFanoutByHandle ( NODE *aNode, const VIA_HANDLE& h
|
|||
|
||||
for( ITEM* item : jt->LinkList() )
|
||||
{
|
||||
if( item->OfKind( ITEM::SEGMENT_T ) )
|
||||
if( item->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
|
||||
{
|
||||
int segIndex;
|
||||
SEGMENT* seg = ( SEGMENT*) item;
|
||||
LINKED_ITEM* seg = ( LINKED_ITEM*) item;
|
||||
LINE l = aNode->AssembleLine( seg, &segIndex );
|
||||
|
||||
if( segIndex != 0 )
|
||||
|
@ -151,6 +165,9 @@ bool DRAGGER::Start( const VECTOR2I& aP, ITEM* aStartItem )
|
|||
case ITEM::VIA_T:
|
||||
return startDragVia( static_cast<VIA*>( aStartItem ) );
|
||||
|
||||
case ITEM::ARC_T:
|
||||
return startDragArc( aP, static_cast<ARC*>( aStartItem ) );
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -179,15 +196,16 @@ bool DRAGGER::dragMarkObstacles( const VECTOR2I& aP )
|
|||
case DM_SEGMENT:
|
||||
case DM_CORNER:
|
||||
{
|
||||
//TODO: Make threshhold configurable
|
||||
int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 4 : 0;
|
||||
LINE origLine( m_draggedLine );
|
||||
LINE dragged( m_draggedLine );
|
||||
dragged.ClearSegmentLinks();
|
||||
dragged.SetSnapThreshhold( thresh );
|
||||
|
||||
if( m_mode == DM_SEGMENT )
|
||||
dragged.DragSegment( aP, m_draggedSegmentIndex, thresh );
|
||||
dragged.DragSegment( aP, m_draggedSegmentIndex );
|
||||
else
|
||||
dragged.DragCorner( aP, m_draggedSegmentIndex, thresh, m_freeAngleMode );
|
||||
dragged.DragCorner( aP, m_draggedSegmentIndex, m_freeAngleMode );
|
||||
|
||||
m_lastNode->Remove( origLine );
|
||||
m_lastNode->Add( dragged );
|
||||
|
@ -233,7 +251,7 @@ void DRAGGER::dumbDragVia( const VIA_HANDLE& aHandle, NODE* aNode, const VECTOR2
|
|||
LINE origLine( *l );
|
||||
LINE draggedLine( *l );
|
||||
|
||||
draggedLine.DragCorner( aP, origLine.CLine().Find( aHandle.pos ), 0, m_freeAngleMode );
|
||||
draggedLine.DragCorner( aP, origLine.CLine().Find( aHandle.pos ), m_freeAngleMode );
|
||||
draggedLine.ClearSegmentLinks();
|
||||
|
||||
m_draggedItems.Add( draggedLine );
|
||||
|
@ -270,13 +288,15 @@ bool DRAGGER::dragShove( const VECTOR2I& aP )
|
|||
case DM_SEGMENT:
|
||||
case DM_CORNER:
|
||||
{
|
||||
int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 4 : 0;
|
||||
//TODO: Make threshhold configurable
|
||||
int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 2 : 0;
|
||||
LINE dragged( m_draggedLine );
|
||||
dragged.SetSnapThreshhold( thresh );
|
||||
|
||||
if( m_mode == DM_SEGMENT )
|
||||
dragged.DragSegment( aP, m_draggedSegmentIndex, thresh );
|
||||
dragged.DragSegment( aP, m_draggedSegmentIndex );
|
||||
else
|
||||
dragged.DragCorner( aP, m_draggedSegmentIndex, thresh );
|
||||
dragged.DragCorner( aP, m_draggedSegmentIndex );
|
||||
|
||||
SHOVE::SHOVE_STATUS st = m_shove->ShoveLines( dragged );
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ private:
|
|||
bool dragMarkObstacles( const VECTOR2I& aP );
|
||||
bool dragShove(const VECTOR2I& aP );
|
||||
bool startDragSegment( const VECTOR2D& aP, SEGMENT* aSeg );
|
||||
bool startDragArc( const VECTOR2D& aP, ARC* aArc );
|
||||
bool startDragVia( VIA* aVia );
|
||||
void dumbDragVia( const VIA_HANDLE& aHandle, NODE* aNode, const VECTOR2I& aP );
|
||||
|
||||
|
@ -126,7 +127,11 @@ private:
|
|||
bool m_dragStatus;
|
||||
PNS_MODE m_currentMode;
|
||||
ITEM_SET m_origViaConnections;
|
||||
|
||||
///< Contains the list of items that are currently modified by the dragger
|
||||
ITEM_SET m_draggedItems;
|
||||
|
||||
///< If true, moves the connection lines without maintaining 45° corners
|
||||
bool m_freeAngleMode;
|
||||
};
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ INDEX::ITEM_SHAPE_INDEX* INDEX::getSubindex( const ITEM* aItem )
|
|||
}
|
||||
break;
|
||||
|
||||
case ITEM::ARC_T:
|
||||
case ITEM::SEGMENT_T:
|
||||
case ITEM::LINE_T:
|
||||
idx_n = SI_Traces + 2 * l.Start() + SI_SegStraight;
|
||||
|
|
|
@ -72,6 +72,7 @@ std::string ITEM::KindStr() const
|
|||
{
|
||||
switch( m_kind )
|
||||
{
|
||||
case ARC_T: return "arc";
|
||||
case LINE_T: return "line";
|
||||
case SEGMENT_T: return "segment";
|
||||
case VIA_T: return "via";
|
||||
|
|
|
@ -62,8 +62,9 @@ public:
|
|||
LINE_T = 2,
|
||||
JOINT_T = 4,
|
||||
SEGMENT_T = 8,
|
||||
VIA_T = 16,
|
||||
DIFF_PAIR_T = 32,
|
||||
ARC_T = 16,
|
||||
VIA_T = 32,
|
||||
DIFF_PAIR_T = 64,
|
||||
ANY_T = 0xff
|
||||
};
|
||||
|
||||
|
|
|
@ -100,11 +100,11 @@ public:
|
|||
/// segments of the same net, on the same layer.
|
||||
bool IsLineCorner() const
|
||||
{
|
||||
if( m_linkedItems.Size() != 2 || m_linkedItems.Count( SEGMENT_T ) != 2 )
|
||||
if( m_linkedItems.Size() != 2 || m_linkedItems.Count( SEGMENT_T | ARC_T ) != 2 )
|
||||
return false;
|
||||
|
||||
SEGMENT* seg1 = static_cast<SEGMENT*>( m_linkedItems[0] );
|
||||
SEGMENT* seg2 = static_cast<SEGMENT*>( m_linkedItems[1] );
|
||||
auto seg1 = static_cast<LINKED_ITEM*>( m_linkedItems[0] );
|
||||
auto seg2 = static_cast<LINKED_ITEM*>( m_linkedItems[1] );
|
||||
|
||||
// joints between segments of different widths are not considered trivial.
|
||||
return seg1->Width() == seg2->Width();
|
||||
|
@ -114,6 +114,7 @@ public:
|
|||
{
|
||||
int vias = m_linkedItems.Count( VIA_T );
|
||||
int segs = m_linkedItems.Count( SEGMENT_T );
|
||||
segs += m_linkedItems.Count( ARC_T );
|
||||
|
||||
return ( m_linkedItems.Size() == 3 && vias == 1 && segs == 2 );
|
||||
}
|
||||
|
@ -156,12 +157,12 @@ public:
|
|||
|
||||
///> For trivial joints, returns the segment adjacent to (aCurrent). For non-trival ones, returns
|
||||
///> NULL, indicating the end of line.
|
||||
SEGMENT* NextSegment( SEGMENT* aCurrent ) const
|
||||
LINKED_ITEM* NextSegment( ITEM* aCurrent ) const
|
||||
{
|
||||
if( !IsLineCorner() )
|
||||
return NULL;
|
||||
|
||||
return static_cast<SEGMENT*>( m_linkedItems[m_linkedItems[0] == aCurrent ? 1 : 0] );
|
||||
return static_cast<LINKED_ITEM*>( m_linkedItems[m_linkedItems[0] == aCurrent ? 1 : 0] );
|
||||
}
|
||||
|
||||
VIA* Via()
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||
*
|
||||
* Copyright (C) 2013-2016 CERN
|
||||
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
|
@ -52,6 +52,8 @@
|
|||
#include "tools/pcb_tool_base.h"
|
||||
|
||||
#include "pns_kicad_iface.h"
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_routing_settings.h"
|
||||
#include "pns_item.h"
|
||||
#include "pns_solid.h"
|
||||
|
@ -815,6 +817,24 @@ std::unique_ptr<PNS::SEGMENT> PNS_KICAD_IFACE::syncTrack( TRACK* aTrack )
|
|||
}
|
||||
|
||||
|
||||
std::unique_ptr<PNS::ARC> PNS_KICAD_IFACE::syncArc( ARC* aArc )
|
||||
{
|
||||
std::unique_ptr< PNS::ARC > arc(
|
||||
new PNS::ARC( SHAPE_ARC( aArc->GetCenter(), aArc->GetStart(),
|
||||
aArc->GetAngle(), aArc->GetWidth() ),
|
||||
aArc->GetNetCode() )
|
||||
);
|
||||
|
||||
arc->SetLayers( LAYER_RANGE( aArc->GetLayer() ) );
|
||||
arc->SetParent( aArc );
|
||||
|
||||
if( aArc->IsLocked() )
|
||||
arc->Mark( PNS::MK_LOCKED );
|
||||
|
||||
return arc;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<PNS::VIA> PNS_KICAD_IFACE::syncVia( VIA* aVia )
|
||||
{
|
||||
PCB_LAYER_ID top, bottom;
|
||||
|
@ -1180,6 +1200,11 @@ void PNS_KICAD_IFACE::SyncWorld( PNS::NODE *aWorld )
|
|||
if( auto segment = syncTrack( t ) )
|
||||
aWorld->Add( std::move( segment ) );
|
||||
}
|
||||
else if( type == PCB_ARC_T )
|
||||
{
|
||||
if( auto arc = syncArc( static_cast<ARC*>( t ) ) )
|
||||
aWorld->Add( std::move( arc ) );
|
||||
}
|
||||
else if( type == PCB_VIA_T )
|
||||
{
|
||||
if( auto via = syncVia( static_cast<VIA*>( t ) ) )
|
||||
|
@ -1290,6 +1315,17 @@ void PNS_KICAD_IFACE::AddItem( PNS::ITEM* aItem )
|
|||
|
||||
switch( aItem->Kind() )
|
||||
{
|
||||
case PNS::ITEM::ARC_T:
|
||||
{
|
||||
auto arc = static_cast<PNS::ARC*>( aItem );
|
||||
ARC* new_arc = new ARC( m_board, static_cast<const SHAPE_ARC*>( arc->Shape() ) );
|
||||
new_arc->SetWidth( arc->Width() );
|
||||
new_arc->SetLayer( ToLAYER_ID( arc->Layers().Start() ) );
|
||||
new_arc->SetNetCode( std::max<int>( 0, arc->Net() ) );
|
||||
newBI = new_arc;
|
||||
break;
|
||||
}
|
||||
|
||||
case PNS::ITEM::SEGMENT_T:
|
||||
{
|
||||
PNS::SEGMENT* seg = static_cast<PNS::SEGMENT*>( aItem );
|
||||
|
|
|
@ -71,6 +71,7 @@ private:
|
|||
|
||||
std::unique_ptr<PNS::SOLID> syncPad( D_PAD* aPad );
|
||||
std::unique_ptr<PNS::SEGMENT> syncTrack( TRACK* aTrack );
|
||||
std::unique_ptr<PNS::ARC> syncArc( ARC* aArc );
|
||||
std::unique_ptr<PNS::VIA> syncVia( VIA* aVia );
|
||||
bool syncTextItem( PNS::NODE* aWorld, EDA_TEXT* aText, PCB_LAYER_ID aLayer );
|
||||
bool syncGraphicalItem( PNS::NODE* aWorld, DRAWSEGMENT* aItem );
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||
*
|
||||
* Copyright (C) 2013-2017 CERN
|
||||
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Copyright (C) 2016-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
|
@ -34,10 +34,11 @@
|
|||
|
||||
namespace PNS {
|
||||
|
||||
LINE::LINE( const LINE& aOther ) :
|
||||
ITEM( aOther ),
|
||||
LINE::LINE( const LINE& aOther )
|
||||
: ITEM( aOther ),
|
||||
m_line( aOther.m_line ),
|
||||
m_width( aOther.m_width )
|
||||
m_width( aOther.m_width ),
|
||||
m_snapThreshhold( aOther.m_snapThreshhold )
|
||||
{
|
||||
m_net = aOther.m_net;
|
||||
m_movable = aOther.m_movable;
|
||||
|
@ -68,6 +69,7 @@ LINE& LINE::operator=( const LINE& aOther )
|
|||
m_marker = aOther.m_marker;
|
||||
m_rank = aOther.m_rank;
|
||||
m_owner = aOther.m_owner;
|
||||
m_snapThreshhold = aOther.m_snapThreshhold;
|
||||
|
||||
copyLinks( &aOther );
|
||||
|
||||
|
@ -87,7 +89,7 @@ void LINE::Mark( int aMarker )
|
|||
{
|
||||
m_marker = aMarker;
|
||||
|
||||
for( SEGMENT* s : m_segmentRefs )
|
||||
for( auto s : m_segmentRefs )
|
||||
s->Mark( aMarker );
|
||||
|
||||
}
|
||||
|
@ -95,7 +97,7 @@ void LINE::Mark( int aMarker )
|
|||
|
||||
void LINE::Unmark( int aMarker )
|
||||
{
|
||||
for( SEGMENT* s : m_segmentRefs )
|
||||
for( auto s : m_segmentRefs )
|
||||
s->Unmark( aMarker );
|
||||
|
||||
m_marker = 0;
|
||||
|
@ -106,7 +108,7 @@ int LINE::Marker() const
|
|||
{
|
||||
int marker = m_marker;
|
||||
|
||||
for( SEGMENT* s : m_segmentRefs )
|
||||
for( auto s : m_segmentRefs )
|
||||
{
|
||||
marker |= s->Marker();
|
||||
}
|
||||
|
@ -306,6 +308,9 @@ bool LINE::Is45Degree() const
|
|||
{
|
||||
const SEG& s = m_line.CSegment( i );
|
||||
|
||||
if( m_line.isArc( i ) )
|
||||
continue;
|
||||
|
||||
if( s.Length() < 10 )
|
||||
continue;
|
||||
|
||||
|
@ -443,12 +448,11 @@ SHAPE_LINE_CHAIN dragCornerInternal( const SHAPE_LINE_CHAIN& aOrigin, const VECT
|
|||
return DIRECTION_45().BuildInitialTrace( aOrigin.CPoint( 0 ), aP, dir.IsDiagonal() );
|
||||
}
|
||||
|
||||
|
||||
void LINE::dragCorner45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold )
|
||||
void LINE::dragCorner45( const VECTOR2I& aP, int aIndex )
|
||||
{
|
||||
SHAPE_LINE_CHAIN path;
|
||||
|
||||
VECTOR2I snapped = snapDraggedCorner( m_line, aP, aIndex, aSnappingThreshold );
|
||||
VECTOR2I snapped = snapDraggedCorner( m_line, aP, aIndex );
|
||||
|
||||
if( aIndex == 0 )
|
||||
path = dragCornerInternal( m_line.Reverse(), snapped ).Reverse();
|
||||
|
@ -458,8 +462,8 @@ void LINE::dragCorner45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
|
|||
{
|
||||
// fixme: awkward behaviour for "outwards" drags
|
||||
path = dragCornerInternal( m_line.Slice( 0, aIndex ), snapped );
|
||||
SHAPE_LINE_CHAIN path_rev = dragCornerInternal( m_line.Slice( aIndex, -1 ).Reverse(),
|
||||
snapped ).Reverse();
|
||||
SHAPE_LINE_CHAIN path_rev =
|
||||
dragCornerInternal( m_line.Slice( aIndex, -1 ).Reverse(), snapped ).Reverse();
|
||||
path.Append( path_rev );
|
||||
}
|
||||
|
||||
|
@ -467,26 +471,25 @@ void LINE::dragCorner45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
|
|||
m_line = path;
|
||||
}
|
||||
|
||||
|
||||
void LINE::dragCornerFree( const VECTOR2I& aP, int aIndex, int aSnappingThreshold )
|
||||
void LINE::dragCornerFree( const VECTOR2I& aP, int aIndex )
|
||||
{
|
||||
m_line.SetPoint( aIndex, aP );
|
||||
m_line.Simplify();
|
||||
}
|
||||
|
||||
void LINE::DragCorner( const VECTOR2I& aP, int aIndex, int aSnappingThreshold, bool aFreeAngle )
|
||||
void LINE::DragCorner( const VECTOR2I& aP, int aIndex, bool aFreeAngle )
|
||||
{
|
||||
if( aFreeAngle )
|
||||
{
|
||||
dragCornerFree ( aP, aIndex, aSnappingThreshold );
|
||||
dragCornerFree( aP, aIndex );
|
||||
}
|
||||
else
|
||||
{
|
||||
dragCorner45 ( aP, aIndex, aSnappingThreshold );
|
||||
dragCorner45( aP, aIndex );
|
||||
}
|
||||
}
|
||||
|
||||
void LINE::DragSegment( const VECTOR2I& aP, int aIndex, int aSnappingThreshold, bool aFreeAngle )
|
||||
void LINE::DragSegment( const VECTOR2I& aP, int aIndex, bool aFreeAngle )
|
||||
{
|
||||
if( aFreeAngle )
|
||||
{
|
||||
|
@ -494,13 +497,12 @@ void LINE::DragSegment( const VECTOR2I& aP, int aIndex, int aSnappingThreshold,
|
|||
}
|
||||
else
|
||||
{
|
||||
dragSegment45 ( aP, aIndex, aSnappingThreshold );
|
||||
dragSegment45( aP, aIndex );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I LINE::snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP,
|
||||
int aIndex, int aThreshold ) const
|
||||
VECTOR2I LINE::snapDraggedCorner(
|
||||
const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, int aIndex ) const
|
||||
{
|
||||
int s_start = std::max( aIndex - 2, 0 );
|
||||
int s_end = std::min( aIndex + 2, aPath.SegmentCount() - 1 );
|
||||
|
@ -509,7 +511,7 @@ VECTOR2I LINE::snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I&
|
|||
int best_dist = INT_MAX;
|
||||
VECTOR2I best_snap = aP;
|
||||
|
||||
if( aThreshold <= 0 )
|
||||
if( m_snapThreshhold <= 0 )
|
||||
return aP;
|
||||
|
||||
for( i = s_start; i <= s_end; i++ )
|
||||
|
@ -520,16 +522,16 @@ VECTOR2I LINE::snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I&
|
|||
{
|
||||
const SEG& b = aPath.CSegment( j );
|
||||
|
||||
if( !( DIRECTION_45( a ).IsObtuse(DIRECTION_45( b ) ) ) )
|
||||
if( !( DIRECTION_45( a ).IsObtuse( DIRECTION_45( b ) ) ) )
|
||||
continue;
|
||||
|
||||
OPT_VECTOR2I ip = a.IntersectLines(b);
|
||||
OPT_VECTOR2I ip = a.IntersectLines( b );
|
||||
|
||||
if( ip )
|
||||
{
|
||||
int dist = ( *ip - aP ).EuclideanNorm();
|
||||
|
||||
if( dist < aThreshold && dist < best_dist )
|
||||
if( dist < m_snapThreshhold && dist < best_dist )
|
||||
{
|
||||
best_dist = dist;
|
||||
best_snap = *ip;
|
||||
|
@ -541,14 +543,14 @@ VECTOR2I LINE::snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I&
|
|||
return best_snap;
|
||||
}
|
||||
|
||||
VECTOR2I LINE::snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP,
|
||||
int aIndex, int aThreshold ) const
|
||||
VECTOR2I LINE::snapToNeighbourSegments(
|
||||
const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, int aIndex ) const
|
||||
{
|
||||
VECTOR2I snap_p[2];
|
||||
DIRECTION_45 dragDir( aPath.CSegment( aIndex ) );
|
||||
int snap_d[2] = { -1, -1 };
|
||||
|
||||
if( aThreshold == 0 )
|
||||
if( m_snapThreshhold == 0 )
|
||||
return aP;
|
||||
|
||||
if( aIndex >= 2 )
|
||||
|
@ -566,7 +568,7 @@ VECTOR2I LINE::snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VEC
|
|||
SEG s = aPath.CSegment( aIndex + 2 );
|
||||
|
||||
if( DIRECTION_45( s ) == dragDir )
|
||||
snap_d[1] = s.LineDistance(aP);
|
||||
snap_d[1] = s.LineDistance( aP );
|
||||
|
||||
snap_p[1] = s.A;
|
||||
}
|
||||
|
@ -576,7 +578,7 @@ VECTOR2I LINE::snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VEC
|
|||
|
||||
for( int i = 0; i < 2; i++ )
|
||||
{
|
||||
if( snap_d[i] >= 0 && snap_d[i] < minDist && snap_d[i] <= aThreshold )
|
||||
if( snap_d[i] >= 0 && snap_d[i] < minDist && snap_d[i] <= m_snapThreshhold )
|
||||
{
|
||||
minDist = snap_d[i];
|
||||
best = snap_p[i];
|
||||
|
@ -586,8 +588,7 @@ VECTOR2I LINE::snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VEC
|
|||
return best;
|
||||
}
|
||||
|
||||
|
||||
void LINE::dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold )
|
||||
void LINE::dragSegment45( const VECTOR2I& aP, int aIndex )
|
||||
{
|
||||
SHAPE_LINE_CHAIN path( m_line );
|
||||
VECTOR2I target( aP );
|
||||
|
@ -595,7 +596,7 @@ void LINE::dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
|
|||
SEG guideA[2], guideB[2];
|
||||
int index = aIndex;
|
||||
|
||||
target = snapToNeighbourSegments( path, aP, aIndex, aSnappingThreshold );
|
||||
target = snapToNeighbourSegments( path, aP, aIndex );
|
||||
|
||||
if( index == 0 )
|
||||
{
|
||||
|
@ -634,25 +635,15 @@ void LINE::dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
|
|||
s_next = path.CSegment( index + 1 );
|
||||
dragged = path.CSegment( index );
|
||||
|
||||
const bool lockEndpointA = true;
|
||||
const bool lockEndpointB = true;
|
||||
|
||||
if( aIndex == 0 )
|
||||
{
|
||||
if( !lockEndpointA )
|
||||
{
|
||||
guideA[0] = guideA[1] = SEG( dragged.A,
|
||||
dragged.A + drag_dir.Right().Right().ToVector() );
|
||||
}
|
||||
else
|
||||
{
|
||||
guideA[0] = SEG( dragged.A, dragged.A + drag_dir.Right().ToVector() );
|
||||
guideA[1] = SEG( dragged.A, dragged.A + drag_dir.Left().ToVector() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( dir_prev.Angle( drag_dir ) & (DIRECTION_45::ANG_OBTUSE | DIRECTION_45::ANG_HALF_FULL) )
|
||||
if( dir_prev.Angle( drag_dir )
|
||||
& ( DIRECTION_45::ANG_OBTUSE | DIRECTION_45::ANG_HALF_FULL ) )
|
||||
{
|
||||
guideA[0] = SEG( s_prev.A, s_prev.A + drag_dir.Left().ToVector() );
|
||||
guideA[1] = SEG( s_prev.A, s_prev.A + drag_dir.Right().ToVector() );
|
||||
|
@ -662,28 +653,20 @@ void LINE::dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
|
|||
}
|
||||
|
||||
if( aIndex == m_line.SegmentCount() - 1 )
|
||||
{
|
||||
if( !lockEndpointB )
|
||||
{
|
||||
guideB[0] = guideB[1] = SEG( dragged.B,
|
||||
dragged.B + drag_dir.Right().Right().ToVector() );
|
||||
}
|
||||
else
|
||||
{
|
||||
guideB[0] = SEG( dragged.B, dragged.B + drag_dir.Right().ToVector() );
|
||||
guideB[1] = SEG( dragged.B, dragged.B + drag_dir.Left().ToVector() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( dir_next.Angle( drag_dir ) & (DIRECTION_45::ANG_OBTUSE | DIRECTION_45::ANG_HALF_FULL) )
|
||||
if( dir_next.Angle( drag_dir )
|
||||
& ( DIRECTION_45::ANG_OBTUSE | DIRECTION_45::ANG_HALF_FULL ) )
|
||||
{
|
||||
guideB[0] = SEG( s_next.B, s_next.B + drag_dir.Left().ToVector() );
|
||||
guideB[1] = SEG( s_next.B, s_next.B + drag_dir.Right().ToVector() );
|
||||
}
|
||||
else
|
||||
guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + dir_next.ToVector() );
|
||||
|
||||
}
|
||||
|
||||
SEG s_current( target, target + drag_dir.ToVector() );
|
||||
|
@ -709,19 +692,19 @@ void LINE::dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
|
|||
|
||||
OPT_VECTOR2I ip;
|
||||
|
||||
if( (ip = s1.Intersect( s_next )) )
|
||||
if( ( ip = s1.Intersect( s_next ) ) )
|
||||
{
|
||||
np.Append( s1.A );
|
||||
np.Append( *ip );
|
||||
np.Append( s_next.B );
|
||||
}
|
||||
else if( (ip = s3.Intersect( s_prev )) )
|
||||
else if( ( ip = s3.Intersect( s_prev ) ) )
|
||||
{
|
||||
np.Append( s_prev.A );
|
||||
np.Append( *ip );
|
||||
np.Append( s3.B );
|
||||
}
|
||||
else if( (ip = s1.Intersect( s3 )) )
|
||||
else if( ( ip = s1.Intersect( s3 ) ) )
|
||||
{
|
||||
np.Append( s_prev.A );
|
||||
np.Append( *ip );
|
||||
|
@ -743,11 +726,6 @@ void LINE::dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
|
|||
}
|
||||
}
|
||||
|
||||
if( !lockEndpointA && aIndex == 0 )
|
||||
best.Remove( 0, 0 );
|
||||
if( !lockEndpointB && aIndex == m_line.SegmentCount() - 1 )
|
||||
best.Remove( -1, -1 );
|
||||
|
||||
if( m_line.PointCount() == 1 )
|
||||
m_line = best;
|
||||
else if( aIndex == 0 )
|
||||
|
@ -792,7 +770,7 @@ void LINE::SetRank( int aRank )
|
|||
{
|
||||
m_rank = aRank;
|
||||
|
||||
for( SEGMENT* s : m_segmentRefs )
|
||||
for( auto s : m_segmentRefs )
|
||||
s->SetRank( aRank );
|
||||
|
||||
}
|
||||
|
@ -803,7 +781,7 @@ int LINE::Rank() const
|
|||
int min_rank = INT_MAX;
|
||||
|
||||
if( IsLinked() ) {
|
||||
for( SEGMENT *s : m_segmentRefs )
|
||||
for( auto s : m_segmentRefs )
|
||||
{
|
||||
min_rank = std::min( min_rank, s->Rank() );
|
||||
}
|
||||
|
@ -955,7 +933,7 @@ OPT_BOX2I LINE::ChangedArea( const LINE* aOther ) const
|
|||
|
||||
bool LINE::HasLockedSegments() const
|
||||
{
|
||||
for( const SEGMENT* seg : m_segmentRefs )
|
||||
for( const auto seg : m_segmentRefs )
|
||||
{
|
||||
if( seg->Marker() & MK_LOCKED )
|
||||
return true;
|
||||
|
|
|
@ -35,8 +35,8 @@
|
|||
|
||||
namespace PNS {
|
||||
|
||||
class LINKED_ITEM;
|
||||
class NODE;
|
||||
class SEGMENT;
|
||||
class VIA;
|
||||
|
||||
/**
|
||||
|
@ -61,7 +61,7 @@ class VIA;
|
|||
class LINE : public ITEM
|
||||
{
|
||||
public:
|
||||
typedef std::vector<SEGMENT*> SEGMENT_REFS;
|
||||
typedef std::vector<LINKED_ITEM*> SEGMENT_REFS;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -71,6 +71,7 @@ public:
|
|||
{
|
||||
m_hasVia = false;
|
||||
m_width = 1; // Dummy value
|
||||
m_snapThreshhold = 0;
|
||||
}
|
||||
|
||||
LINE( const LINE& aOther );
|
||||
|
@ -80,10 +81,11 @@ public:
|
|||
* Copies properties (net, layers, etc.) from a base line and replaces the shape
|
||||
* by another
|
||||
**/
|
||||
LINE( const LINE& aBase, const SHAPE_LINE_CHAIN& aLine ) :
|
||||
ITEM( aBase ),
|
||||
LINE( const LINE& aBase, const SHAPE_LINE_CHAIN& aLine )
|
||||
: ITEM( aBase ),
|
||||
m_line( aLine ),
|
||||
m_width( aBase.m_width )
|
||||
m_width( aBase.m_width ),
|
||||
m_snapThreshhold( aBase.m_snapThreshhold )
|
||||
{
|
||||
m_net = aBase.m_net;
|
||||
m_layers = aBase.m_layers;
|
||||
|
@ -104,6 +106,7 @@ public:
|
|||
m_net = aVia.Net();
|
||||
m_layers = aVia.Layers();
|
||||
m_rank = aVia.Rank();
|
||||
m_snapThreshhold = 0;
|
||||
}
|
||||
|
||||
~LINE();
|
||||
|
@ -155,6 +158,12 @@ public:
|
|||
return m_line.PointCount();
|
||||
}
|
||||
|
||||
///> Returns the number of arcs in the line
|
||||
int ArcCount() const
|
||||
{
|
||||
return m_line.ArcCount();
|
||||
}
|
||||
|
||||
///> Returns the aIdx-th point of the line
|
||||
const VECTOR2I& CPoint( int aIdx ) const
|
||||
{
|
||||
|
@ -190,7 +199,7 @@ public:
|
|||
/* Linking functions */
|
||||
|
||||
///> Adds a reference to a segment registered in a NODE that is a part of this line.
|
||||
void LinkSegment( SEGMENT* aSeg )
|
||||
void LinkSegment( LINKED_ITEM* aSeg )
|
||||
{
|
||||
m_segmentRefs.push_back( aSeg );
|
||||
}
|
||||
|
@ -213,13 +222,13 @@ public:
|
|||
}
|
||||
|
||||
///> Checks if the segment aSeg is a part of the line.
|
||||
bool ContainsSegment( SEGMENT* aSeg ) const
|
||||
bool ContainsSegment( LINKED_ITEM* aSeg ) const
|
||||
{
|
||||
return std::find( m_segmentRefs.begin(), m_segmentRefs.end(),
|
||||
aSeg ) != m_segmentRefs.end();
|
||||
}
|
||||
|
||||
SEGMENT* GetLink( int aIndex ) const
|
||||
LINKED_ITEM* GetLink( int aIndex ) const
|
||||
{
|
||||
return m_segmentRefs[aIndex];
|
||||
}
|
||||
|
@ -275,8 +284,8 @@ public:
|
|||
virtual void Unmark( int aMarker = -1 ) override;
|
||||
virtual int Marker() const override;
|
||||
|
||||
void DragSegment( const VECTOR2I& aP, int aIndex, int aSnappingThreshold = 0, bool aFreeAngle = false );
|
||||
void DragCorner( const VECTOR2I& aP, int aIndex, int aSnappingThreshold = 0, bool aFreeAngle = false );
|
||||
void DragSegment( const VECTOR2I& aP, int aIndex, bool aFreeAngle = false );
|
||||
void DragCorner( const VECTOR2I& aP, int aIndex, bool aFreeAngle = false );
|
||||
|
||||
void SetRank( int aRank ) override;
|
||||
int Rank() const override;
|
||||
|
@ -286,18 +295,27 @@ public:
|
|||
|
||||
OPT_BOX2I ChangedArea( const LINE* aOther ) const;
|
||||
|
||||
void SetSnapThreshhold( int aThreshhold )
|
||||
{
|
||||
m_snapThreshhold = aThreshhold;
|
||||
}
|
||||
|
||||
int GetSnapThreshhold() const
|
||||
{
|
||||
return m_snapThreshhold;
|
||||
}
|
||||
|
||||
private:
|
||||
void dragSegment45( const VECTOR2I& aP, int aIndex );
|
||||
void dragCorner45( const VECTOR2I& aP, int aIndex );
|
||||
void dragSegmentFree( const VECTOR2I& aP, int aIndex );
|
||||
void dragCornerFree( const VECTOR2I& aP, int aIndex );
|
||||
|
||||
void dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold );
|
||||
void dragCorner45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold );
|
||||
void dragSegmentFree( const VECTOR2I& aP, int aIndex, int aSnappingThreshold );
|
||||
void dragCornerFree( const VECTOR2I& aP, int aIndex, int aSnappingThreshold );
|
||||
VECTOR2I snapToNeighbourSegments(
|
||||
const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, int aIndex ) const;
|
||||
|
||||
VECTOR2I snapToNeighbourSegments( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP,
|
||||
int aIndex, int aThreshold) const;
|
||||
|
||||
VECTOR2I snapDraggedCorner( const SHAPE_LINE_CHAIN& aPath, const VECTOR2I &aP,
|
||||
int aIndex, int aThreshold ) const;
|
||||
VECTOR2I snapDraggedCorner(
|
||||
const SHAPE_LINE_CHAIN& aPath, const VECTOR2I& aP, int aIndex ) const;
|
||||
|
||||
///> Copies m_segmentRefs from the line aParent.
|
||||
void copyLinks( const LINE* aParent ) ;
|
||||
|
@ -315,6 +333,9 @@ private:
|
|||
///> If true, the line ends with a via
|
||||
bool m_hasVia;
|
||||
|
||||
///> Width to smooth out jagged segments
|
||||
int m_snapThreshhold;
|
||||
|
||||
///> Via at the end point, if m_hasVia == true
|
||||
VIA m_via;
|
||||
};
|
||||
|
|
|
@ -21,14 +21,15 @@
|
|||
|
||||
#include <core/optional.h>
|
||||
|
||||
#include "pns_node.h"
|
||||
#include "pns_line_placer.h"
|
||||
#include "pns_walkaround.h"
|
||||
#include "pns_shove.h"
|
||||
#include "pns_utils.h"
|
||||
#include "pns_router.h"
|
||||
#include "pns_topology.h"
|
||||
#include "pns_arc.h"
|
||||
#include "pns_debug_decorator.h"
|
||||
#include "pns_line_placer.h"
|
||||
#include "pns_node.h"
|
||||
#include "pns_router.h"
|
||||
#include "pns_shove.h"
|
||||
#include "pns_topology.h"
|
||||
#include "pns_utils.h"
|
||||
#include "pns_walkaround.h"
|
||||
|
||||
#include <class_board_item.h>
|
||||
|
||||
|
@ -344,13 +345,8 @@ bool LINE_PLACER::mergeHead()
|
|||
return false;
|
||||
}
|
||||
|
||||
if( !n_tail )
|
||||
tail.Append( head.CSegment( 0 ).A );
|
||||
|
||||
for( int i = 0; i < n_head - 2; i++ )
|
||||
{
|
||||
tail.Append( head.CSegment( i ).B );
|
||||
}
|
||||
tail.Append( head );
|
||||
tail.Remove( -1 );
|
||||
|
||||
tail.Simplify();
|
||||
|
||||
|
@ -359,7 +355,7 @@ bool LINE_PLACER::mergeHead()
|
|||
m_p_start = last.B;
|
||||
m_direction = DIRECTION_45( last ).Right();
|
||||
|
||||
head.Remove( 0, n_head - 2 );
|
||||
head.Remove( 0, -1 );
|
||||
|
||||
wxLogTrace( "PNS", "Placer: merge %d, new direction: %s", n_head, m_direction.Format().c_str() );
|
||||
|
||||
|
@ -1064,18 +1060,33 @@ bool LINE_PLACER::FixRoute( const VECTOR2I& aP, ITEM* aEndItem, bool aForceFinis
|
|||
lastV = std::max( 1, l.SegmentCount() - 1 );
|
||||
|
||||
SEGMENT* lastSeg = nullptr;
|
||||
int lastArc = -1;
|
||||
|
||||
for( int i = 0; i < lastV; i++ )
|
||||
{
|
||||
ssize_t arcIndex = l.ArcIndex( i );
|
||||
|
||||
if( arcIndex < 0 )
|
||||
{
|
||||
const SEG& s = pl.CSegment( i );
|
||||
lastSeg = new SEGMENT( s, m_currentNet );
|
||||
std::unique_ptr< SEGMENT > seg( lastSeg );
|
||||
auto seg = std::make_unique<SEGMENT>( s, m_currentNet );
|
||||
seg->SetWidth( pl.Width() );
|
||||
seg->SetLayer( m_currentLayer );
|
||||
if( ! m_lastNode->Add( std::move( seg ) ) )
|
||||
{
|
||||
if( !m_lastNode->Add( std::move( seg ) ) )
|
||||
lastSeg = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( arcIndex == lastArc )
|
||||
continue;
|
||||
|
||||
auto arc = std::make_unique<ARC>( l.Arc( arcIndex ), m_currentNet );
|
||||
arc->SetWidth( pl.Width() );
|
||||
arc->SetLayer( m_currentLayer );
|
||||
m_lastNode->Add( std::move( arc ) );
|
||||
lastSeg = nullptr;
|
||||
lastArc = arcIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if( pl.EndsWithVia() )
|
||||
|
@ -1115,12 +1126,12 @@ void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest )
|
|||
if( aLatest.CLine().CPoint( 0 ) == aLatest.CLine().CPoint( -1 ) )
|
||||
return;
|
||||
|
||||
std::set<SEGMENT *> toErase;
|
||||
std::set<LINKED_ITEM *> toErase;
|
||||
aNode->Add( aLatest, true );
|
||||
|
||||
for( int s = 0; s < aLatest.LinkCount(); s++ )
|
||||
{
|
||||
SEGMENT* seg = aLatest.GetLink(s);
|
||||
auto seg = aLatest.GetLink(s);
|
||||
LINE ourLine = aNode->AssembleLine( seg );
|
||||
JOINT a, b;
|
||||
std::vector<LINE> lines;
|
||||
|
@ -1143,7 +1154,7 @@ void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest )
|
|||
|
||||
if( !( line.ContainsSegment( seg ) ) && line.SegmentCount() )
|
||||
{
|
||||
for( SEGMENT *ss : line.LinkedSegments() )
|
||||
for( auto ss : line.LinkedSegments() )
|
||||
toErase.insert( ss );
|
||||
|
||||
removedCount++;
|
||||
|
@ -1153,7 +1164,7 @@ void LINE_PLACER::removeLoops( NODE* aNode, LINE& aLatest )
|
|||
wxLogTrace( "PNS", "total segs removed: %d/%d", removedCount, total );
|
||||
}
|
||||
|
||||
for( SEGMENT *s : toErase )
|
||||
for( auto s : toErase )
|
||||
aNode->Remove( s );
|
||||
|
||||
aNode->Remove( aLatest );
|
||||
|
@ -1207,6 +1218,7 @@ void LINE_PLACER::SetOrthoMode( bool aOrthoMode )
|
|||
bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead, bool aInvertPosture )
|
||||
{
|
||||
SHAPE_LINE_CHAIN l;
|
||||
int initial_radius = 0;
|
||||
|
||||
if( m_p_start == aP )
|
||||
{
|
||||
|
@ -1220,10 +1232,14 @@ bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead, bool aInver
|
|||
}
|
||||
else
|
||||
{
|
||||
// Rounded corners don't make sense when routing orthogonally (single track at a time)
|
||||
if( Settings().GetRounded() && !m_orthoMode )
|
||||
initial_radius = Settings().GetMaxRadius();
|
||||
|
||||
if ( aInvertPosture )
|
||||
l = m_direction.Right().BuildInitialTrace( m_p_start, aP );
|
||||
l = m_direction.Right().BuildInitialTrace( m_p_start, aP, false, initial_radius );
|
||||
else
|
||||
l = m_direction.BuildInitialTrace( m_p_start, aP );
|
||||
l = m_direction.BuildInitialTrace( m_p_start, aP, false, initial_radius );
|
||||
}
|
||||
|
||||
if( l.SegmentCount() > 1 && m_orthoMode )
|
||||
|
@ -1256,7 +1272,7 @@ bool LINE_PLACER::buildInitialLine( const VECTOR2I& aP, LINE& aHead, bool aInver
|
|||
|
||||
if( v.PushoutForce( m_currentNode, lead, force, solidsOnly, 40 ) )
|
||||
{
|
||||
SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP + force );
|
||||
SHAPE_LINE_CHAIN line = m_direction.BuildInitialTrace( m_p_start, aP + force, initial_radius );
|
||||
aHead = LINE( aHead, line );
|
||||
|
||||
v.SetPos( v.Pos() + force );
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||
*
|
||||
* Copyright (C) 2019 CERN
|
||||
* Author: Seth Hillbrand <hillbrand@ucdavis.edu>
|
||||
*
|
||||
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PCBNEW_ROUTER_PNS_LINKED_ITEM_H_
|
||||
#define PCBNEW_ROUTER_PNS_LINKED_ITEM_H_
|
||||
|
||||
#include "pns_item.h"
|
||||
|
||||
|
||||
namespace PNS
|
||||
{
|
||||
class LINKED_ITEM : public ITEM
|
||||
{
|
||||
public:
|
||||
|
||||
LINKED_ITEM( PnsKind aKind ) : ITEM( aKind )
|
||||
{}
|
||||
|
||||
virtual void SetWidth( int aWidth )
|
||||
{};
|
||||
|
||||
virtual int Width() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PNS
|
||||
#endif /* PCBNEW_ROUTER_PNS_LINKED_ITEM_H_ */
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* KiRouter - a push-and-(sometimes-)shove PCB router
|
||||
*
|
||||
* Copyright (C) 2013-2014 CERN
|
||||
* Copyright (C) 2013-2019 CERN
|
||||
* Copyright (C) 2016 KiCad Developers, see AUTHORS.txt for contributors.
|
||||
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
||||
*
|
||||
|
@ -21,12 +21,14 @@
|
|||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include <math/vector2d.h>
|
||||
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_item.h"
|
||||
#include "pns_line.h"
|
||||
#include "pns_node.h"
|
||||
|
@ -564,8 +566,26 @@ void NODE::Add( LINE& aLine, bool aAllowRedundant )
|
|||
|
||||
SHAPE_LINE_CHAIN& l = aLine.Line();
|
||||
|
||||
for( size_t i = 0; i < l.ArcCount(); i++ )
|
||||
{
|
||||
auto s = l.Arc( i );
|
||||
ARC* rarc;
|
||||
|
||||
if( !aAllowRedundant && ( rarc = findRedundantArc( s.GetP0(), s.GetP1(), aLine.Layers(), aLine.Net() ) ) )
|
||||
aLine.LinkSegment( rarc );
|
||||
else
|
||||
{
|
||||
auto newarc = std::make_unique< ARC >( aLine, s );
|
||||
aLine.LinkSegment( newarc.get() );
|
||||
Add( std::move( newarc ), true );
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < l.SegmentCount(); i++ )
|
||||
{
|
||||
if( l.isArc( i ) )
|
||||
continue;
|
||||
|
||||
SEG s = l.CSegment( i );
|
||||
|
||||
if( s.A != s.B )
|
||||
|
@ -612,6 +632,20 @@ bool NODE::Add( std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant )
|
|||
return true;
|
||||
}
|
||||
|
||||
void NODE::addArc( ARC* aArc )
|
||||
{
|
||||
linkJoint( aArc->Anchor( 0 ), aArc->Layers(), aArc->Net(), aArc );
|
||||
linkJoint( aArc->Anchor( 1 ), aArc->Layers(), aArc->Net(), aArc );
|
||||
|
||||
m_index->Add( aArc );
|
||||
}
|
||||
|
||||
void NODE::Add( std::unique_ptr< ARC > aArc )
|
||||
{
|
||||
aArc->SetOwner( this );
|
||||
addArc( aArc.release() );
|
||||
}
|
||||
|
||||
void NODE::Add( std::unique_ptr< ITEM > aItem, bool aAllowRedundant )
|
||||
{
|
||||
switch( aItem->Kind() )
|
||||
|
@ -620,6 +654,11 @@ void NODE::Add( std::unique_ptr< ITEM > aItem, bool aAllowRedundant )
|
|||
case ITEM::SEGMENT_T: Add( ItemCast<SEGMENT>( std::move( aItem ) ), aAllowRedundant ); break;
|
||||
case ITEM::VIA_T: Add( ItemCast<VIA>( std::move( aItem ) ) ); break;
|
||||
|
||||
case ITEM::ARC_T:
|
||||
//todo(snh): Add redundant search
|
||||
Add( ItemCast<ARC>( std::move( aItem ) ) );
|
||||
break;
|
||||
|
||||
case ITEM::LINE_T:
|
||||
default:
|
||||
assert( false );
|
||||
|
@ -654,6 +693,14 @@ void NODE::removeSegmentIndex( SEGMENT* aSeg )
|
|||
unlinkJoint( aSeg->Seg().B, aSeg->Layers(), aSeg->Net(), aSeg );
|
||||
}
|
||||
|
||||
|
||||
void NODE::removeArcIndex( ARC* aArc )
|
||||
{
|
||||
unlinkJoint( aArc->Anchor( 0 ), aArc->Layers(), aArc->Net(), aArc );
|
||||
unlinkJoint( aArc->Anchor( 1 ), aArc->Layers(), aArc->Net(), aArc );
|
||||
}
|
||||
|
||||
|
||||
void NODE::removeViaIndex( VIA* aVia )
|
||||
{
|
||||
// We have to split a single joint (associated with a via, binding together multiple layers)
|
||||
|
@ -738,10 +785,20 @@ void NODE::Remove( SEGMENT* aSegment )
|
|||
doRemove( aSegment );
|
||||
}
|
||||
|
||||
void NODE::Remove( ARC* aArc )
|
||||
{
|
||||
removeArcIndex( aArc );
|
||||
doRemove( aArc );
|
||||
}
|
||||
|
||||
void NODE::Remove( ITEM* aItem )
|
||||
{
|
||||
switch( aItem->Kind() )
|
||||
{
|
||||
case ITEM::ARC_T:
|
||||
Remove( static_cast<ARC*>( aItem ) );
|
||||
break;
|
||||
|
||||
case ITEM::SOLID_T:
|
||||
Remove( static_cast<SOLID*>( aItem ) );
|
||||
break;
|
||||
|
@ -773,11 +830,14 @@ void NODE::Remove( ITEM* aItem )
|
|||
void NODE::Remove( LINE& aLine )
|
||||
{
|
||||
// LINE does not have a seperate remover, as LINEs are never truly a member of the tree
|
||||
std::vector<SEGMENT*>& segRefs = aLine.LinkedSegments();
|
||||
std::vector<LINKED_ITEM*>& segRefs = aLine.LinkedSegments();
|
||||
|
||||
for( SEGMENT* seg : segRefs )
|
||||
for( auto li : segRefs )
|
||||
{
|
||||
Remove( seg );
|
||||
if( li->OfKind( ITEM::SEGMENT_T ) )
|
||||
Remove( static_cast<SEGMENT*>( li ) );
|
||||
else if( li->OfKind( ITEM::ARC_T ) )
|
||||
Remove( static_cast<ARC*>( li ) );
|
||||
}
|
||||
|
||||
aLine.SetOwner( nullptr );
|
||||
|
@ -785,18 +845,16 @@ void NODE::Remove( LINE& aLine )
|
|||
}
|
||||
|
||||
|
||||
void NODE::followLine( SEGMENT* aCurrent, bool aScanDirection, int& aPos,
|
||||
int aLimit, VECTOR2I* aCorners, SEGMENT** aSegments, bool& aGuardHit,
|
||||
bool aStopAtLockedJoints )
|
||||
void NODE::followLine( LINKED_ITEM* aCurrent, int aScanDirection, int& aPos, int aLimit, VECTOR2I* aCorners,
|
||||
LINKED_ITEM** aSegments, bool& aGuardHit, bool aStopAtLockedJoints )
|
||||
{
|
||||
bool prevReversed = false;
|
||||
|
||||
const VECTOR2I guard = aScanDirection ? aCurrent->Seg().B : aCurrent->Seg().A;
|
||||
const VECTOR2I guard = aCurrent->Anchor( aScanDirection );
|
||||
|
||||
for( int count = 0 ; ; ++count )
|
||||
{
|
||||
const VECTOR2I p =
|
||||
( aScanDirection ^ prevReversed ) ? aCurrent->Seg().B : aCurrent->Seg().A;
|
||||
const VECTOR2I p = aCurrent->Anchor( aScanDirection ^ prevReversed );
|
||||
const JOINT* jt = FindJoint( p, aCurrent );
|
||||
|
||||
assert( jt );
|
||||
|
@ -819,18 +877,17 @@ void NODE::followLine( SEGMENT* aCurrent, bool aScanDirection, int& aPos,
|
|||
|
||||
aCurrent = jt->NextSegment( aCurrent );
|
||||
|
||||
prevReversed =
|
||||
( jt->Pos() == ( aScanDirection ? aCurrent->Seg().B : aCurrent->Seg().A ) );
|
||||
prevReversed = ( jt->Pos() == aCurrent->Anchor( aScanDirection ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const LINE NODE::AssembleLine( SEGMENT* aSeg, int* aOriginSegmentIndex, bool aStopAtLockedJoints )
|
||||
const LINE NODE::AssembleLine( LINKED_ITEM* aSeg, int* aOriginSegmentIndex, bool aStopAtLockedJoints )
|
||||
{
|
||||
const int MaxVerts = 1024 * 16;
|
||||
|
||||
VECTOR2I corners[MaxVerts + 1];
|
||||
SEGMENT* segs[MaxVerts + 1];
|
||||
LINKED_ITEM* segs[MaxVerts + 1];
|
||||
|
||||
LINE pl;
|
||||
bool guardHit = false;
|
||||
|
@ -849,7 +906,7 @@ const LINE NODE::AssembleLine( SEGMENT* aSeg, int* aOriginSegmentIndex, bool aSt
|
|||
|
||||
int n = 0;
|
||||
|
||||
SEGMENT* prev_seg = NULL;
|
||||
LINKED_ITEM* prev_seg = NULL;
|
||||
bool originSet = false;
|
||||
|
||||
for( int i = i_start + 1; i < i_end; i++ )
|
||||
|
@ -1301,6 +1358,37 @@ SEGMENT* NODE::findRedundantSegment( SEGMENT* aSeg )
|
|||
return findRedundantSegment( aSeg->Seg().A, aSeg->Seg().B, aSeg->Layers(), aSeg->Net() );
|
||||
}
|
||||
|
||||
ARC* NODE::findRedundantArc( const VECTOR2I& A, const VECTOR2I& B, const LAYER_RANGE& lr,
|
||||
int aNet )
|
||||
{
|
||||
JOINT* jtStart = FindJoint( A, lr.Start(), aNet );
|
||||
|
||||
if( !jtStart )
|
||||
return nullptr;
|
||||
|
||||
for( ITEM* item : jtStart->LinkList() )
|
||||
{
|
||||
if( item->OfKind( ITEM::ARC_T ) )
|
||||
{
|
||||
ARC* seg2 = static_cast<ARC*>( item );
|
||||
|
||||
const VECTOR2I a2( seg2->Anchor( 0 ) );
|
||||
const VECTOR2I b2( seg2->Anchor( 1 ) );
|
||||
|
||||
if( seg2->Layers().Start() == lr.Start() &&
|
||||
((A == a2 && B == b2) || (A == b2 && B == a2)) )
|
||||
return seg2;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ARC* NODE::findRedundantArc( ARC* aArc )
|
||||
{
|
||||
return findRedundantArc( aArc->Anchor( 0 ), aArc->Anchor( 1 ), aArc->Layers(), aArc->Net() );
|
||||
}
|
||||
|
||||
|
||||
ITEM *NODE::FindItemByParent( const BOARD_CONNECTED_ITEM* aParent )
|
||||
{
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
namespace PNS {
|
||||
|
||||
class ARC;
|
||||
class SEGMENT;
|
||||
class LINE;
|
||||
class SOLID;
|
||||
|
@ -285,6 +286,7 @@ public:
|
|||
bool Add( std::unique_ptr< SEGMENT > aSegment, bool aAllowRedundant = false );
|
||||
void Add( std::unique_ptr< SOLID > aSolid );
|
||||
void Add( std::unique_ptr< VIA > aVia );
|
||||
void Add( std::unique_ptr< ARC > aArc );
|
||||
|
||||
void Add( LINE& aLine, bool aAllowRedundant = false );
|
||||
|
||||
|
@ -297,6 +299,7 @@ public:
|
|||
*
|
||||
* Just as the name says, removes an item from this branch.
|
||||
*/
|
||||
void Remove( ARC* aArc );
|
||||
void Remove( SOLID* aSolid );
|
||||
void Remove( VIA* aVia );
|
||||
void Remove( SEGMENT* aSegment );
|
||||
|
@ -340,7 +343,7 @@ public:
|
|||
* @param aOriginSegmentIndex index of aSeg in the resulting line
|
||||
* @return the line
|
||||
*/
|
||||
const LINE AssembleLine( SEGMENT* aSeg, int* aOriginSegmentIndex = NULL,
|
||||
const LINE AssembleLine( LINKED_ITEM* aSeg, int* aOriginSegmentIndex = NULL,
|
||||
bool aStopAtLockedJoints = false );
|
||||
|
||||
///> Prints the contents and joints structure
|
||||
|
@ -449,11 +452,13 @@ private:
|
|||
void addSolid( SOLID* aSeg );
|
||||
void addSegment( SEGMENT* aSeg );
|
||||
void addVia( VIA* aVia );
|
||||
void addArc( ARC* aVia );
|
||||
|
||||
void removeLine( LINE& aLine );
|
||||
void removeSolidIndex( SOLID* aSeg );
|
||||
void removeSegmentIndex( SEGMENT* aSeg );
|
||||
void removeViaIndex( VIA* aVia );
|
||||
void removeArcIndex( ARC* aVia );
|
||||
|
||||
void doRemove( ITEM* aItem );
|
||||
void unlinkParent();
|
||||
|
@ -469,15 +474,13 @@ private:
|
|||
const LAYER_RANGE & lr, int aNet );
|
||||
SEGMENT* findRedundantSegment( SEGMENT* aSeg );
|
||||
|
||||
ARC* findRedundantArc( const VECTOR2I& A, const VECTOR2I& B,
|
||||
const LAYER_RANGE & lr, int aNet );
|
||||
ARC* findRedundantArc( ARC* aSeg );
|
||||
|
||||
///> scans the joint map, forming a line starting from segment (current).
|
||||
void followLine( SEGMENT* aCurrent,
|
||||
bool aScanDirection,
|
||||
int& aPos,
|
||||
int aLimit,
|
||||
VECTOR2I* aCorners,
|
||||
SEGMENT** aSegments,
|
||||
bool& aGuardHit,
|
||||
bool aStopAtLockedJoints );
|
||||
void followLine( LINKED_ITEM* aCurrent, int aScanDirection, int& aPos, int aLimit, VECTOR2I* aCorners,
|
||||
LINKED_ITEM** aSegments, bool& aGuardHit, bool aStopAtLockedJoints );
|
||||
|
||||
///> hash table with the joints, linking the items. Joints are hashed by
|
||||
///> their position, layer set and net.
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <geometry/shape_simple.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_line.h"
|
||||
#include "pns_diff_pair.h"
|
||||
#include "pns_node.h"
|
||||
|
@ -190,7 +191,7 @@ void OPTIMIZER::removeCachedSegments( LINE* aLine, int aStartVertex, int aEndVer
|
|||
|
||||
for( int i = aStartVertex; i < aEndVertex - 1; i++ )
|
||||
{
|
||||
SEGMENT* s = segs[i];
|
||||
LINKED_ITEM* s = segs[i];
|
||||
m_cacheTags.erase( s );
|
||||
m_cache.Remove( s );
|
||||
}
|
||||
|
@ -273,17 +274,19 @@ int LINE_RESTRICTIONS::allowedAngles( NODE* aWorld, const LINE* aLine, const VEC
|
|||
|
||||
for( const ITEM* item : jt->Links().CItems() )
|
||||
{
|
||||
if( item->OfKind( ITEM::VIA_T ) || item->OfKind( ITEM::SOLID_T ) )
|
||||
if( item->OfKind( ITEM::VIA_T | ITEM::SOLID_T ) )
|
||||
return 0xff;
|
||||
else if( const SEGMENT* seg = dyn_cast<const SEGMENT*>( item ) )
|
||||
else if( auto segment = dynamic_cast<const SEGMENT*>( item ) )
|
||||
{
|
||||
SEG s = seg->Seg();
|
||||
SEG s( segment->Seg() );
|
||||
if( s.A != aP )
|
||||
s.Reverse();
|
||||
|
||||
if( n_dirs < 8 )
|
||||
dirs[n_dirs++] = aFirst ? DIRECTION_45( s ) : DIRECTION_45( s ).Opposite();
|
||||
dirs[n_dirs] = aFirst ? DIRECTION_45( s ) : DIRECTION_45( s ).Opposite();
|
||||
}
|
||||
|
||||
if( ++n_dirs >= 8 )
|
||||
break;
|
||||
}
|
||||
|
||||
const int angleMask = DIRECTION_45::ANG_OBTUSE | DIRECTION_45::ANG_HALF_FULL | DIRECTION_45::ANG_STRAIGHT;
|
||||
|
@ -452,10 +455,13 @@ bool OPTIMIZER::mergeObtuse( LINE* aLine )
|
|||
}
|
||||
|
||||
bool found_anything = false;
|
||||
int n = 0;
|
||||
|
||||
while( n < n_segs - step )
|
||||
for( int n = 0; n < n_segs - step; n++ )
|
||||
{
|
||||
// Don't try to optimize the arc segments
|
||||
if( current_path.isArc( n ) || current_path.isArc( n + step ) )
|
||||
continue;
|
||||
|
||||
const SEG s1 = current_path.CSegment( n );
|
||||
const SEG s2 = current_path.CSegment( n + step );
|
||||
SEG s1opt, s2opt;
|
||||
|
@ -494,8 +500,6 @@ bool OPTIMIZER::mergeObtuse( LINE* aLine )
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
if( !found_anything )
|
||||
|
@ -580,7 +584,6 @@ bool OPTIMIZER::Optimize( LINE* aLine, LINE* aResult )
|
|||
|
||||
bool OPTIMIZER::mergeStep( LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, int step )
|
||||
{
|
||||
int n = 0;
|
||||
int n_segs = aCurrentPath.SegmentCount();
|
||||
|
||||
int cost_orig = COST_ESTIMATOR::CornerCost( aCurrentPath );
|
||||
|
@ -595,8 +598,12 @@ bool OPTIMIZER::mergeStep( LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, int step
|
|||
|
||||
restr.Build( m_world, aLine, aCurrentPath, m_restrictArea, m_restrictAreaActive );
|
||||
|
||||
while( n < n_segs - step )
|
||||
for( int n = 0; n < n_segs - step; n++ )
|
||||
{
|
||||
// Do not attempt to merge false segments that are part of an arc
|
||||
if( aCurrentPath.isArc( n ) || aCurrentPath.isArc( n + step ) )
|
||||
continue;
|
||||
|
||||
const SEG s1 = aCurrentPath.CSegment( n );
|
||||
const SEG s2 = aCurrentPath.CSegment( n + step );
|
||||
|
||||
|
@ -637,8 +644,6 @@ bool OPTIMIZER::mergeStep( LINE* aLine, SHAPE_LINE_CHAIN& aCurrentPath, int step
|
|||
aCurrentPath = *picked;
|
||||
return true;
|
||||
}
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -509,6 +509,12 @@ bool ROUTER::IsPlacingVia() const
|
|||
}
|
||||
|
||||
|
||||
void ROUTER::ToggleRounded()
|
||||
{
|
||||
m_settings->SetRounded( !m_settings->GetRounded() );
|
||||
}
|
||||
|
||||
|
||||
void ROUTER::SetOrthoMode( bool aEnable )
|
||||
{
|
||||
if( !m_placer )
|
||||
|
|
|
@ -53,6 +53,7 @@ class DIFF_PAIR_PLACER;
|
|||
class PLACEMENT_ALGO;
|
||||
class LINE_PLACER;
|
||||
class ITEM;
|
||||
class ARC;
|
||||
class LINE;
|
||||
class SOLID;
|
||||
class SEGMENT;
|
||||
|
@ -76,7 +77,8 @@ enum DRAG_MODE
|
|||
DM_SEGMENT = 0x2,
|
||||
DM_VIA = 0x4,
|
||||
DM_FREE_ANGLE = 0x8,
|
||||
DM_ANY = 0x7
|
||||
DM_ARC = 0x10,
|
||||
DM_ANY = 0x17
|
||||
};
|
||||
/**
|
||||
* ROUTER
|
||||
|
@ -158,6 +160,8 @@ public:
|
|||
void ToggleViaPlacement();
|
||||
void SetOrthoMode( bool aEnable );
|
||||
|
||||
void ToggleRounded();
|
||||
|
||||
int GetCurrentLayer() const;
|
||||
const std::vector<int> GetCurrentNets() const;
|
||||
|
||||
|
|
|
@ -50,6 +50,9 @@ ROUTING_SETTINGS::ROUTING_SETTINGS( JSON_SETTINGS* aParent, const std::string& a
|
|||
m_inlineDragEnabled = false;
|
||||
m_snapToTracks = false;
|
||||
m_snapToPads = false;
|
||||
m_minRadius = 0;
|
||||
m_maxRadius = 1000000;
|
||||
m_roundedCorners = false;
|
||||
|
||||
m_params.emplace_back( new PARAM<int>( "mode", reinterpret_cast<int*>( &m_routingMode ),
|
||||
static_cast<int>( RM_Walkaround ) ) );
|
||||
|
@ -83,6 +86,11 @@ ROUTING_SETTINGS::ROUTING_SETTINGS( JSON_SETTINGS* aParent, const std::string& a
|
|||
m_params.emplace_back( new PARAM<bool>( "inline_drag", &m_inlineDragEnabled, false ) );
|
||||
m_params.emplace_back( new PARAM<bool>( "snap_to_tracks", &m_snapToTracks, false ) );
|
||||
m_params.emplace_back( new PARAM<bool>( "snap_to_pads", &m_snapToPads, false ) );
|
||||
|
||||
m_params.emplace_back( new PARAM<int>( "min_radius", &m_minRadius, 0 ) );
|
||||
m_params.emplace_back( new PARAM<int>( "max_radius", &m_maxRadius, 1000000 ) );
|
||||
m_params.emplace_back( new PARAM<bool>( "use_rounded", &m_roundedCorners, false ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -141,6 +141,28 @@ public:
|
|||
bool GetSnapToTracks() const { return m_snapToTracks; }
|
||||
bool GetSnapToPads() const { return m_snapToPads; }
|
||||
|
||||
bool GetRounded() const { return m_roundedCorners; }
|
||||
void SetRounded( bool aRound ) { m_roundedCorners = aRound; }
|
||||
|
||||
void SetMinRadius( int aRadius )
|
||||
{
|
||||
m_minRadius = aRadius;
|
||||
|
||||
if( m_maxRadius < m_minRadius )
|
||||
m_maxRadius = m_minRadius;
|
||||
}
|
||||
|
||||
void SetMaxRadius( int aRadius )
|
||||
{
|
||||
m_maxRadius = aRadius;
|
||||
|
||||
if( m_maxRadius < m_minRadius )
|
||||
m_minRadius = m_maxRadius;
|
||||
}
|
||||
|
||||
int GetMinRadius() const { return m_minRadius; }
|
||||
int GetMaxRadius() const { return m_maxRadius; }
|
||||
|
||||
private:
|
||||
bool m_shoveVias;
|
||||
bool m_startDiagonal;
|
||||
|
@ -155,6 +177,10 @@ private:
|
|||
bool m_inlineDragEnabled;
|
||||
bool m_snapToTracks;
|
||||
bool m_snapToPads;
|
||||
bool m_roundedCorners;
|
||||
|
||||
int m_minRadius;
|
||||
int m_maxRadius;
|
||||
|
||||
PNS_MODE m_routingMode;
|
||||
PNS_OPTIMIZATION_EFFORT m_optimizerEffort;
|
||||
|
|
|
@ -28,28 +28,28 @@
|
|||
#include <geometry/shape_segment.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
#include "pns_item.h"
|
||||
#include "pns_line.h"
|
||||
#include "pns_linked_item.h"
|
||||
|
||||
namespace PNS {
|
||||
|
||||
class NODE;
|
||||
|
||||
class SEGMENT : public ITEM
|
||||
class SEGMENT : public LINKED_ITEM
|
||||
{
|
||||
public:
|
||||
SEGMENT() :
|
||||
ITEM( SEGMENT_T )
|
||||
LINKED_ITEM( SEGMENT_T )
|
||||
{}
|
||||
|
||||
SEGMENT( const SEG& aSeg, int aNet ) :
|
||||
ITEM( SEGMENT_T ), m_seg( aSeg, 0 )
|
||||
LINKED_ITEM( SEGMENT_T ), m_seg( aSeg, 0 )
|
||||
{
|
||||
m_net = aNet;
|
||||
}
|
||||
|
||||
SEGMENT( const LINE& aParentLine, const SEG& aSeg ) :
|
||||
ITEM( SEGMENT_T ),
|
||||
LINKED_ITEM( SEGMENT_T ),
|
||||
m_seg( aSeg, aParentLine.Width() )
|
||||
{
|
||||
m_net = aParentLine.Net();
|
||||
|
@ -70,22 +70,12 @@ public:
|
|||
return static_cast<const SHAPE*>( &m_seg );
|
||||
}
|
||||
|
||||
void SetLayer( int aLayer )
|
||||
{
|
||||
SetLayers( LAYER_RANGE( aLayer ) );
|
||||
}
|
||||
|
||||
int Layer() const override
|
||||
{
|
||||
return Layers().Start();
|
||||
}
|
||||
|
||||
void SetWidth( int aWidth )
|
||||
void SetWidth( int aWidth ) override
|
||||
{
|
||||
m_seg.SetWidth(aWidth);
|
||||
}
|
||||
|
||||
int Width() const
|
||||
int Width() const override
|
||||
{
|
||||
return m_seg.GetWidth();
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <cassert>
|
||||
#include <math/box2.h>
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_line.h"
|
||||
#include "pns_node.h"
|
||||
#include "pns_debug_decorator.h"
|
||||
|
@ -98,9 +99,9 @@ SHOVE::~SHOVE()
|
|||
}
|
||||
|
||||
|
||||
LINE SHOVE::assembleLine( const SEGMENT* aSeg, int* aIndex )
|
||||
LINE SHOVE::assembleLine( const LINKED_ITEM* aSeg, int* aIndex )
|
||||
{
|
||||
return m_currentNode->AssembleLine( const_cast<SEGMENT*>( aSeg ), aIndex, true );
|
||||
return m_currentNode->AssembleLine( const_cast<LINKED_ITEM*>( aSeg ), aIndex, true );
|
||||
}
|
||||
|
||||
// A dumb function that checks if the shoved line is shoved the right way, e.g.
|
||||
|
@ -267,7 +268,7 @@ SHOVE::SHOVE_STATUS SHOVE::ProcessSingleLine( LINE& aCurrent, LINE& aObstacle, L
|
|||
|
||||
bool obstacleIsHead = false;
|
||||
|
||||
for( SEGMENT* s : aObstacle.LinkedSegments() )
|
||||
for( auto s : aObstacle.LinkedSegments() )
|
||||
{
|
||||
if( s->Marker() & MK_HEAD )
|
||||
{
|
||||
|
@ -377,6 +378,67 @@ SHOVE::SHOVE_STATUS SHOVE::onCollidingSegment( LINE& aCurrent, SEGMENT* aObstacl
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* TODO describe....
|
||||
*/
|
||||
SHOVE::SHOVE_STATUS SHOVE::onCollidingArc( LINE& aCurrent, ARC* aObstacleArc )
|
||||
{
|
||||
int segIndex;
|
||||
LINE obstacleLine = assembleLine( aObstacleArc, &segIndex );
|
||||
LINE shovedLine( obstacleLine );
|
||||
ARC tmp( *aObstacleArc );
|
||||
|
||||
if( obstacleLine.HasLockedSegments() )
|
||||
return SH_TRY_WALK;
|
||||
|
||||
SHOVE_STATUS rv = ProcessSingleLine( aCurrent, obstacleLine, shovedLine );
|
||||
|
||||
const double extensionWalkThreshold = 1.0;
|
||||
|
||||
double obsLen = obstacleLine.CLine().Length();
|
||||
double shovedLen = shovedLine.CLine().Length();
|
||||
double extensionFactor = 0.0;
|
||||
|
||||
if( obsLen != 0.0f )
|
||||
extensionFactor = shovedLen / obsLen - 1.0;
|
||||
|
||||
if( extensionFactor > extensionWalkThreshold )
|
||||
return SH_TRY_WALK;
|
||||
|
||||
assert( obstacleLine.LayersOverlap( &shovedLine ) );
|
||||
|
||||
#ifdef DEBUG
|
||||
m_logger.NewGroup( "on-colliding-segment", m_iter );
|
||||
m_logger.Log( &tmp, 0, "obstacle-segment" );
|
||||
m_logger.Log( &aCurrent, 1, "current-line" );
|
||||
m_logger.Log( &obstacleLine, 2, "obstacle-line" );
|
||||
m_logger.Log( &shovedLine, 3, "shoved-line" );
|
||||
#endif
|
||||
|
||||
if( rv == SH_OK )
|
||||
{
|
||||
if( shovedLine.Marker() & MK_HEAD )
|
||||
{
|
||||
if( m_multiLineMode )
|
||||
return SH_INCOMPLETE;
|
||||
|
||||
m_newHead = shovedLine;
|
||||
}
|
||||
|
||||
int rank = aCurrent.Rank();
|
||||
shovedLine.SetRank( rank - 1 );
|
||||
|
||||
sanityCheck( &obstacleLine, &shovedLine );
|
||||
replaceLine( obstacleLine, shovedLine );
|
||||
|
||||
if( !pushLineStack( shovedLine ) )
|
||||
rv = SH_INCOMPLETE;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TODO describe....
|
||||
*/
|
||||
|
@ -658,12 +720,13 @@ SHOVE::SHOVE_STATUS SHOVE::pushOrShoveVia( VIA* aVia, const VECTOR2I& aForce, in
|
|||
|
||||
for( ITEM* item : jt->LinkList() )
|
||||
{
|
||||
if( SEGMENT* seg = dyn_cast<SEGMENT*>( item ) )
|
||||
if( item->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
|
||||
{
|
||||
LINKED_ITEM* li = static_cast<LINKED_ITEM*>( item );
|
||||
LINE_PAIR lp;
|
||||
int segIndex;
|
||||
|
||||
lp.first = assembleLine( seg, &segIndex );
|
||||
lp.first = assembleLine( li, &segIndex );
|
||||
|
||||
if( lp.first.HasLockedSegments() )
|
||||
return SH_TRY_WALK;
|
||||
|
@ -835,10 +898,10 @@ SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacle
|
|||
|
||||
for( ITEM* item : jt->LinkList() )
|
||||
{
|
||||
if( item->OfKind( ITEM::SEGMENT_T ) && item->LayersOverlap( &aCurrent ) )
|
||||
if( item->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) && item->LayersOverlap( &aCurrent ) )
|
||||
{
|
||||
SEGMENT* seg = (SEGMENT*) item;
|
||||
LINE head = assembleLine( seg );
|
||||
LINKED_ITEM* li = static_cast<LINKED_ITEM*>( item );
|
||||
LINE head = assembleLine( li );
|
||||
|
||||
head.AppendVia( *aObstacleVia );
|
||||
|
||||
|
@ -903,7 +966,7 @@ SHOVE::SHOVE_STATUS SHOVE::onReverseCollidingVia( LINE& aCurrent, VIA* aObstacle
|
|||
}
|
||||
|
||||
|
||||
void SHOVE::unwindLineStack( SEGMENT* aSeg )
|
||||
void SHOVE::unwindLineStack( LINKED_ITEM* aSeg )
|
||||
{
|
||||
for( std::vector<LINE>::iterator i = m_lineStack.begin(); i != m_lineStack.end() ; )
|
||||
{
|
||||
|
@ -925,13 +988,13 @@ void SHOVE::unwindLineStack( SEGMENT* aSeg )
|
|||
|
||||
void SHOVE::unwindLineStack( ITEM* aItem )
|
||||
{
|
||||
if( aItem->OfKind( ITEM::SEGMENT_T ) )
|
||||
unwindLineStack( static_cast<SEGMENT*>( aItem ));
|
||||
if( aItem->OfKind( ITEM::SEGMENT_T | ITEM::ARC_T ) )
|
||||
unwindLineStack( static_cast<LINKED_ITEM*>( aItem ) );
|
||||
else if( aItem->OfKind( ITEM::LINE_T ) )
|
||||
{
|
||||
LINE* l = static_cast<LINE*>( aItem );
|
||||
|
||||
for( SEGMENT* seg : l->LinkedSegments() )
|
||||
for( auto seg : l->LinkedSegments() )
|
||||
unwindLineStack( seg );
|
||||
}
|
||||
}
|
||||
|
@ -964,7 +1027,7 @@ void SHOVE::popLineStack( )
|
|||
{
|
||||
bool found = false;
|
||||
|
||||
for( SEGMENT *s : l.LinkedSegments() )
|
||||
for( auto s : l.LinkedSegments() )
|
||||
{
|
||||
if( i->ContainsSegment( s ) )
|
||||
{
|
||||
|
@ -1035,7 +1098,21 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
|||
case ITEM::SEGMENT_T:
|
||||
{
|
||||
wxLogTrace( "PNS", "iter %d: reverse-collide-segment ", aIter );
|
||||
LINE revLine = assembleLine( (SEGMENT*) ni );
|
||||
LINE revLine = assembleLine( static_cast<SEGMENT*>( ni ) );
|
||||
|
||||
popLineStack();
|
||||
st = onCollidingLine( revLine, currentLine );
|
||||
if( !pushLineStack( revLine ) )
|
||||
return SH_INCOMPLETE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ITEM::ARC_T:
|
||||
{
|
||||
//TODO(snh): Handle Arc shove separate from track
|
||||
wxLogTrace( "PNS", "iter %d: reverse-collide-arc ", aIter );
|
||||
LINE revLine = assembleLine( static_cast<ARC*>( ni ) );
|
||||
|
||||
popLineStack();
|
||||
st = onCollidingLine( revLine, currentLine );
|
||||
|
@ -1065,6 +1142,17 @@ SHOVE::SHOVE_STATUS SHOVE::shoveIteration( int aIter )
|
|||
|
||||
break;
|
||||
|
||||
//TODO(snh): Customize Arc collide
|
||||
case ITEM::ARC_T:
|
||||
wxLogTrace( "PNS", "iter %d: collide-arc ", aIter );
|
||||
|
||||
st = onCollidingArc( currentLine, static_cast<ARC*>( ni ) );
|
||||
|
||||
if( st == SH_TRY_WALK )
|
||||
st = onCollidingSolid( currentLine, ni );
|
||||
|
||||
break;
|
||||
|
||||
case ITEM::VIA_T:
|
||||
wxLogTrace( "PNS", "iter %d: shove-via ", aIter );
|
||||
st = onCollidingVia( ¤tLine, (VIA*) ni );
|
||||
|
|
|
@ -111,6 +111,7 @@ private:
|
|||
SHOVE_STATUS walkaroundLoneVia( LINE& aCurrent, LINE& aObstacle, LINE& aShoved );
|
||||
bool checkBumpDirection( const LINE& aCurrent, const LINE& aShoved ) const;
|
||||
|
||||
SHOVE_STATUS onCollidingArc( LINE& aCurrent, ARC* aObstacleArc );
|
||||
SHOVE_STATUS onCollidingLine( LINE& aCurrent, LINE& aObstacle );
|
||||
SHOVE_STATUS onCollidingSegment( LINE& aCurrent, SEGMENT* aObstacleSeg );
|
||||
SHOVE_STATUS onCollidingSolid( LINE& aCurrent, ITEM* aObstacle );
|
||||
|
@ -120,7 +121,7 @@ private:
|
|||
|
||||
OPT_BOX2I totalAffectedArea() const;
|
||||
|
||||
void unwindLineStack( SEGMENT* aSeg );
|
||||
void unwindLineStack( LINKED_ITEM* aSeg );
|
||||
void unwindLineStack( ITEM* aItem );
|
||||
|
||||
void runOptimizer( NODE* aNode );
|
||||
|
@ -128,7 +129,7 @@ private:
|
|||
bool pushLineStack( const LINE& aL, bool aKeepCurrentOnTop = false );
|
||||
void popLineStack();
|
||||
|
||||
LINE assembleLine( const SEGMENT* aSeg, int* aIndex = NULL );
|
||||
LINE assembleLine( const LINKED_ITEM* aSeg, int* aIndex = NULL );
|
||||
|
||||
void replaceItems( ITEM* aOld, std::unique_ptr< ITEM > aNew );
|
||||
void replaceLine( LINE& aOld, LINE& aNew );
|
||||
|
|
|
@ -44,6 +44,7 @@ using namespace std::placeholders;
|
|||
#include <tools/pcb_actions.h>
|
||||
#include <tools/grid_helper.h>
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_kicad_iface.h"
|
||||
#include "pns_tool_base.h"
|
||||
#include "pns_segment.h"
|
||||
|
@ -67,6 +68,7 @@ TOOL_BASE::TOOL_BASE( const std::string& aToolName ) :
|
|||
m_gridHelper = nullptr;
|
||||
m_iface = nullptr;
|
||||
m_router = nullptr;
|
||||
m_cancelled = false;
|
||||
|
||||
m_startItem = nullptr;
|
||||
m_startLayer = 0;
|
||||
|
@ -256,7 +258,7 @@ bool TOOL_BASE::checkSnap( ITEM *aItem )
|
|||
|
||||
if( aItem )
|
||||
{
|
||||
if( aItem->OfKind( ITEM::VIA_T ) || aItem->OfKind( ITEM::SEGMENT_T ) )
|
||||
if( aItem->OfKind( ITEM::VIA_T | ITEM::SEGMENT_T | ITEM::ARC_T ) )
|
||||
return pnss.GetSnapToTracks();
|
||||
else if( aItem->OfKind( ITEM::SOLID_T ) )
|
||||
return pnss.GetSnapToPads();
|
||||
|
@ -406,18 +408,23 @@ const VECTOR2I TOOL_BASE::snapToItem( bool aEnabled, ITEM* aItem, VECTOR2I aP)
|
|||
break;
|
||||
|
||||
case ITEM::SEGMENT_T:
|
||||
case ITEM::ARC_T:
|
||||
{
|
||||
SEGMENT* seg = static_cast<SEGMENT*>( aItem );
|
||||
const SEG& s = seg->Seg();
|
||||
int w = seg->Width();
|
||||
LINKED_ITEM* li = static_cast<LINKED_ITEM*>( aItem );
|
||||
int w = li->Width();
|
||||
auto A = li->Anchor( 0 );
|
||||
auto B = li->Anchor( 1 );
|
||||
|
||||
|
||||
if( ( aP - s.A ).EuclideanNorm() < w / 2 )
|
||||
anchor = s.A;
|
||||
else if( ( aP - s.B ).EuclideanNorm() < w / 2 )
|
||||
anchor = s.B;
|
||||
else
|
||||
anchor = m_gridHelper->AlignToSegment( aP, s );
|
||||
if( ( aP - A ).EuclideanNorm() < w / 2 )
|
||||
anchor = A;
|
||||
else if( ( aP - B ).EuclideanNorm() < w / 2 )
|
||||
anchor = B;
|
||||
else // TODO(snh): Clean this up
|
||||
if( aItem->Kind() == ITEM::SEGMENT_T )
|
||||
anchor = m_gridHelper->AlignToSegment( aP, static_cast<SEGMENT*>( li )->Seg() );
|
||||
else if( aItem->Kind() == ITEM::ARC_T )
|
||||
anchor = m_gridHelper->AlignToArc( aP,
|
||||
*static_cast<const SHAPE_ARC*>( static_cast<ARC*>( li )->Shape() ) );
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ bool TOPOLOGY::SimplifyLine( LINE* aLine )
|
|||
if( !aLine->IsLinked() || !aLine->SegmentCount() )
|
||||
return false;
|
||||
|
||||
SEGMENT* root = aLine->GetLink(0);
|
||||
LINKED_ITEM* root = aLine->GetLink( 0 );
|
||||
LINE l = m_world->AssembleLine( root );
|
||||
SHAPE_LINE_CHAIN simplified( l.CLine() );
|
||||
|
||||
|
@ -181,7 +181,8 @@ bool TOPOLOGY::followTrivialPath( LINE* aLine, bool aLeft, ITEM_SET& aSet, std::
|
|||
assert( aLine->IsLinked() );
|
||||
|
||||
VECTOR2I anchor = aLeft ? aLine->CPoint( 0 ) : aLine->CPoint( -1 );
|
||||
SEGMENT* last = aLeft ? aLine->LinkedSegments().front() : aLine->LinkedSegments().back();
|
||||
LINKED_ITEM* last =
|
||||
aLeft ? aLine->LinkedSegments().front() : aLine->LinkedSegments().back();
|
||||
JOINT* jt = m_world->FindJoint( anchor, aLine );
|
||||
|
||||
assert( jt != NULL );
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "pns_via.h"
|
||||
#include "pns_router.h"
|
||||
|
||||
#include <geometry/shape_arc.h>
|
||||
#include <geometry/shape_segment.h>
|
||||
#include <math/box2.h>
|
||||
|
||||
|
@ -51,6 +52,63 @@ const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize
|
|||
}
|
||||
|
||||
|
||||
const SHAPE_LINE_CHAIN ArcHull( const SHAPE_ARC& aSeg, int aClearance,
|
||||
int aWalkaroundThickness )
|
||||
{
|
||||
int d = aSeg.GetWidth() / 2 + aClearance + aWalkaroundThickness / 2 + HULL_MARGIN;
|
||||
int x = (int)( 2.0 / ( 1.0 + M_SQRT2 ) * d ) / 2;
|
||||
|
||||
auto line = aSeg.ConvertToPolyline();
|
||||
|
||||
SHAPE_LINE_CHAIN s;
|
||||
s.SetClosed( true );
|
||||
std::vector<VECTOR2I> reverse_line;
|
||||
|
||||
auto seg = line.Segment( 0 );
|
||||
VECTOR2I dir = seg.B - seg.A;
|
||||
VECTOR2I p0 = dir.Perpendicular().Resize( d );
|
||||
VECTOR2I ds = dir.Perpendicular().Resize( x );
|
||||
VECTOR2I pd = dir.Resize( x );
|
||||
VECTOR2I dp = dir.Resize( d );
|
||||
|
||||
// Append the first curve
|
||||
s.Append( seg.A + p0 - pd );
|
||||
s.Append( seg.A - dp + ds );
|
||||
s.Append( seg.A - dp - ds );
|
||||
s.Append( seg.A - p0 - pd );
|
||||
|
||||
for( int i = 1; i < line.SegmentCount(); i++ )
|
||||
{
|
||||
auto old_seg = seg;
|
||||
auto endpt = ( old_seg.A - old_seg.B ).Resize( seg.Length() );
|
||||
old_seg.A = old_seg.B + endpt;
|
||||
|
||||
seg = line.Segment( i );
|
||||
auto dir2 = old_seg.A - seg.B;
|
||||
|
||||
p0 = dir2.Perpendicular().Resize( d );
|
||||
s.Append( seg.A - p0 );
|
||||
reverse_line.push_back( seg.A + p0 );
|
||||
}
|
||||
|
||||
pd = dir.Resize( x );
|
||||
dp = dir.Resize( d );
|
||||
s.Append( seg.B - p0 + pd );
|
||||
s.Append( seg.B + dp - ds );
|
||||
s.Append( seg.B + dp + ds );
|
||||
s.Append( seg.B + p0 + pd );
|
||||
|
||||
for( int i = reverse_line.size() - 1; i >= 0; i-- )
|
||||
s.Append( reverse_line[i] );
|
||||
|
||||
// make sure the hull outline is always clockwise
|
||||
if( s.CSegment( 0 ).Side( line.Segment( 0 ).A ) < 0 )
|
||||
return s.Reverse();
|
||||
else
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance,
|
||||
int aWalkaroundThickness )
|
||||
{
|
||||
|
|
|
@ -38,6 +38,8 @@ class LINE;
|
|||
|
||||
/** Various utility functions */
|
||||
|
||||
const SHAPE_LINE_CHAIN ArcHull( const SHAPE_ARC& aSeg, int aClearance, int aWalkaroundThickness );
|
||||
|
||||
const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize,
|
||||
int aClearance, int aChamfer );
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "router_preview_item.h"
|
||||
|
||||
#include "pns_arc.h"
|
||||
#include "pns_line.h"
|
||||
#include "pns_segment.h"
|
||||
#include "pns_via.h"
|
||||
|
@ -90,16 +91,18 @@ void ROUTER_PREVIEW_ITEM::Update( const PNS::ITEM* aItem )
|
|||
{
|
||||
case PNS::ITEM::LINE_T:
|
||||
m_type = PR_SHAPE;
|
||||
m_width = ( (PNS::LINE*) aItem )->Width();
|
||||
m_width = static_cast<const PNS::LINE*>( aItem )->Width();
|
||||
break;
|
||||
|
||||
case PNS::ITEM::ARC_T:
|
||||
m_type = PR_SHAPE;
|
||||
m_width = static_cast<const PNS::ARC*>( aItem )->Width();
|
||||
break;
|
||||
|
||||
case PNS::ITEM::SEGMENT_T:
|
||||
{
|
||||
PNS::SEGMENT* seg = (PNS::SEGMENT*) aItem;
|
||||
m_type = PR_SHAPE;
|
||||
m_width = seg->Width();
|
||||
m_width = static_cast<const PNS::SEGMENT*>( aItem )->Width();
|
||||
break;
|
||||
}
|
||||
|
||||
case PNS::ITEM::VIA_T:
|
||||
m_originLayer = m_layer = LAYER_VIAS;
|
||||
|
|
|
@ -136,6 +136,12 @@ static const TOOL_ACTION ACT_SwitchPosture( "pcbnew.InteractiveRouter.SwitchPost
|
|||
_( "Switches posture of the currently routed track." ),
|
||||
change_entry_orient_xpm );
|
||||
|
||||
static const TOOL_ACTION ACT_SwitchRounding( "pcbnew.InteractiveRouter.SwitchRounding",
|
||||
AS_CONTEXT,
|
||||
0, LEGACY_HK_NAME( "Switch Rounding" ),
|
||||
_( "Switch Rounding" ),
|
||||
_( "Switches the corner type of the currently routed track." ) );
|
||||
|
||||
#undef _
|
||||
#define _(s) wxGetTranslation((s))
|
||||
|
||||
|
@ -787,6 +793,12 @@ void ROUTER_TOOL::performRouting()
|
|||
m_router->Move( m_endSnapPoint, m_endItem );
|
||||
m_startItem = nullptr;
|
||||
}
|
||||
else if( evt->IsAction( &ACT_SwitchRounding ) )
|
||||
{
|
||||
m_router->ToggleRounded();
|
||||
updateEndItem( *evt );
|
||||
m_router->Move( m_endSnapPoint, m_endItem ); // refresh
|
||||
}
|
||||
else if( evt->IsAction( &ACT_SwitchPosture ) )
|
||||
{
|
||||
m_router->FlipPosture();
|
||||
|
@ -1078,8 +1090,9 @@ void ROUTER_TOOL::NeighboringSegmentFilter( const VECTOR2I& aPt, GENERAL_COLLECT
|
|||
// First make sure we've got something that *might* match.
|
||||
int vias = aCollector.CountType( PCB_VIA_T );
|
||||
int traces = aCollector.CountType( PCB_TRACE_T );
|
||||
int arcs = aCollector.CountType( PCB_ARC_T );
|
||||
|
||||
if( vias > 1 || traces > 2 || vias + traces < 1 )
|
||||
if( arcs > 0 || vias > 1 || traces > 2 || vias + traces < 1 )
|
||||
return;
|
||||
|
||||
// Fetch first TRACK (via or trace) as our reference
|
||||
|
|
|
@ -47,6 +47,7 @@
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
obj = SWIG_NewPointerObj( SWIG_as_voidptr(aItem),
|
||||
SWIGTYPE_p_TRACK,
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
*/
|
||||
|
||||
#include <bitmaps.h>
|
||||
#include <class_track.h>
|
||||
#include <class_zone.h>
|
||||
#include <tool/tool_manager.h>
|
||||
#include <tools/pcb_actions.h>
|
||||
|
|
|
@ -33,6 +33,7 @@ using namespace std::placeholders;
|
|||
#include <class_draw_panel_gal.h>
|
||||
#include <class_edge_mod.h>
|
||||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <class_zone.h>
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
|
@ -177,6 +178,39 @@ VECTOR2I GRID_HELPER::AlignToSegment( const VECTOR2I& aPoint, const SEG& aSeg )
|
|||
}
|
||||
|
||||
|
||||
VECTOR2I GRID_HELPER::AlignToArc( const VECTOR2I& aPoint, const SHAPE_ARC& aArc )
|
||||
{
|
||||
OPT_VECTOR2I pts[6];
|
||||
|
||||
if( !m_enableSnap )
|
||||
return aPoint;
|
||||
|
||||
const VECTOR2D gridOffset( GetOrigin() );
|
||||
const VECTOR2D gridSize( GetGrid() );
|
||||
|
||||
VECTOR2I nearest( KiROUND( ( aPoint.x - gridOffset.x ) / gridSize.x ) * gridSize.x + gridOffset.x,
|
||||
KiROUND( ( aPoint.y - gridOffset.y ) / gridSize.y ) * gridSize.y + gridOffset.y );
|
||||
|
||||
auto line = aArc.ConvertToPolyline();
|
||||
int min_d = std::numeric_limits<int>::max();
|
||||
|
||||
for( auto pt : line.CPoints() )
|
||||
{
|
||||
int d = ( pt - aPoint ).EuclideanNorm();
|
||||
|
||||
if( d < min_d )
|
||||
{
|
||||
min_d = d;
|
||||
nearest = pt;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
|
||||
VECTOR2I GRID_HELPER::BestDragOrigin( const VECTOR2I &aMousePos, std::vector<BOARD_ITEM*>& aItems )
|
||||
{
|
||||
clearAnchors();
|
||||
|
@ -460,6 +494,7 @@ void GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bo
|
|||
}
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
if( aFrom || m_frame->Settings().m_MagneticTracks == MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
|
||||
{
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <origin_viewitem.h>
|
||||
#include <layers_id_colors_and_visibility.h>
|
||||
#include <geometry/seg.h>
|
||||
#include <geometry/shape_arc.h>
|
||||
|
||||
class PCB_BASE_FRAME;
|
||||
|
||||
|
@ -60,6 +61,9 @@ public:
|
|||
VECTOR2I AlignToSegment ( const VECTOR2I& aPoint, const SEG& aSeg );
|
||||
|
||||
VECTOR2I BestDragOrigin( const VECTOR2I& aMousePos, std::vector<BOARD_ITEM*>& aItem );
|
||||
|
||||
VECTOR2I AlignToArc ( const VECTOR2I& aPoint, const SHAPE_ARC& aSeg );
|
||||
|
||||
VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, BOARD_ITEM* aDraggedItem );
|
||||
VECTOR2I BestSnapAnchor( const VECTOR2I& aOrigin, const LSET& aLayers,
|
||||
const std::vector<BOARD_ITEM*>& aSkip = {} );
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <board_commit.h>
|
||||
#include <class_board.h>
|
||||
#include <class_module.h>
|
||||
#include <class_track.h>
|
||||
#include <class_pcb_target.h>
|
||||
#include <class_zone.h>
|
||||
#include <collectors.h>
|
||||
|
|
|
@ -822,7 +822,7 @@ int SELECTION_TOOL::expandConnection( const TOOL_EVENT& aEvent )
|
|||
void SELECTION_TOOL::selectConnectedTracks( BOARD_CONNECTED_ITEM& aStartItem,
|
||||
KICAD_T aStopCondition )
|
||||
{
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_VIA_T, PCB_PAD_T, EOT };
|
||||
constexpr KICAD_T types[] = { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, EOT };
|
||||
|
||||
auto connectivity = board()->GetConnectivity();
|
||||
auto connectedItems = connectivity->GetConnectedItems( &aStartItem, types );
|
||||
|
@ -1210,6 +1210,7 @@ static bool itemIsIncludedByFilter( const BOARD_ITEM& aItem, const BOARD& aBoard
|
|||
break;
|
||||
}
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
include = aFilterOptions.includeTracks;
|
||||
break;
|
||||
|
@ -1525,6 +1526,7 @@ bool SELECTION_TOOL::Selectable( const BOARD_ITEM* aItem, bool checkVisibilityOn
|
|||
break;
|
||||
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
{
|
||||
if( !board()->IsElementVisible( LAYER_TRACKS ) )
|
||||
return false;
|
||||
|
@ -2038,6 +2040,7 @@ void SELECTION_TOOL::GuessSelectionCandidates( GENERAL_COLLECTOR& aCollector,
|
|||
switch( item->Type() )
|
||||
{
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_PAD_T:
|
||||
case PCB_LINE_T:
|
||||
case PCB_VIA_T:
|
||||
|
|
|
@ -445,6 +445,7 @@ void PCB_BASE_EDIT_FRAME::PutDataInPreviousState( PICKED_ITEMS_LIST* aList, bool
|
|||
// Fall through
|
||||
case PCB_ZONE_AREA_T:
|
||||
case PCB_TRACE_T:
|
||||
case PCB_ARC_T:
|
||||
case PCB_VIA_T:
|
||||
reBuild_ratsnest = true;
|
||||
break;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <class_drawsegment.h>
|
||||
#include <class_pcb_text.h>
|
||||
#include <class_pcb_target.h>
|
||||
#include <class_track.h>
|
||||
#include <connectivity/connectivity_data.h>
|
||||
#include <board_commit.h>
|
||||
#include <widgets/progress_reporter.h>
|
||||
|
|
|
@ -60,6 +60,7 @@ set( common_srcs
|
|||
geometry/test_shape_poly_set_collision.cpp
|
||||
geometry/test_shape_poly_set_distance.cpp
|
||||
geometry/test_shape_poly_set_iterator.cpp
|
||||
geometry/test_shape_line_chain.cpp
|
||||
|
||||
view/test_zoom_controller.cpp
|
||||
)
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* This program source code file is part of KiCad, a free EDA CAD application.
|
||||
*
|
||||
* Copyright (C) 2019 KiCad Developers, see CHANGELOG.TXT for contributors.
|
||||
*
|
||||
* 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_arc.h>
|
||||
#include <geometry/shape_line_chain.h>
|
||||
|
||||
#include <unit_test_utils/geometry.h>
|
||||
#include <unit_test_utils/numeric.h>
|
||||
#include <unit_test_utils/unit_test_utils.h>
|
||||
|
||||
#include "geom_test_utils.h"
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( ShapeLineChain )
|
||||
|
||||
BOOST_AUTO_TEST_CASE( ArcToPolyline )
|
||||
{
|
||||
SHAPE_LINE_CHAIN base_chain( { VECTOR2I( 0, 0 ), VECTOR2I( 0, 1000 ), VECTOR2I( 1000, 0 ) } );
|
||||
|
||||
SHAPE_LINE_CHAIN chain_insert( {
|
||||
VECTOR2I( 0, 1500 ),
|
||||
VECTOR2I( 1500, 1500 ),
|
||||
VECTOR2I( 1500, 0 ),
|
||||
} );
|
||||
|
||||
SHAPE_LINE_CHAIN arc_insert1( SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), 1800 ) );
|
||||
|
||||
SHAPE_LINE_CHAIN arc_insert2( SHAPE_ARC( VECTOR2I( 0, 500 ), VECTOR2I( 0, 400 ), 1800 ) );
|
||||
|
||||
BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
|
||||
BOOST_CHECK_EQUAL( arc_insert1.CShapes().size(), arc_insert1.CPoints().size() );
|
||||
BOOST_CHECK_EQUAL( arc_insert2.CShapes().size(), arc_insert2.CPoints().size() );
|
||||
|
||||
base_chain.Insert( 0, SHAPE_ARC( VECTOR2I( 0, -100 ), VECTOR2I( 0, -200 ), 1800 ) );
|
||||
|
||||
BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
|
||||
|
||||
base_chain.Replace( 0, 2, chain_insert );
|
||||
BOOST_CHECK_EQUAL( base_chain.CShapes().size(), base_chain.CPoints().size() );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue