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:
Seth Hillbrand 2019-05-16 17:13:21 -07:00
parent 3af868e3d1
commit 8c19b4b6ae
76 changed files with 1488 additions and 416 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
else
l.m_dir = static_cast<Directions>( m_dir - 1 );
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 + 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

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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 );
return 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 );
}

View File

@ -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 );
m_shapes.push_back( ssize_t( SHAPE_IS_PT ) );
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;
}
@ -929,7 +935,7 @@ bool SHAPE_LINE_CHAIN::Parse( std::stringstream& aStream )
aStream >> p0.y;
aStream >> angle;
m_arcs.emplace_back( pc, p0, angle );
m_arcs.emplace_back( pc, p0, angle );
}
return true;

View File

@ -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)

View File

@ -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;

View File

@ -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>

View File

@ -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(

View File

@ -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.

View File

@ -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;

View File

@ -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( std::abs( dist - radius ) > max_dist )
return false;
if( rel_start <= max_dist || rel_mid <= max_dist || rel_end <= max_dist )
return true;
double arc_angle_start = GetArcAngleStart(); // Always 0.0 ... 360 deg, in 0.1 deg
double arc_hittest = ArcTangente( relpos.y, relpos.x );
//TODO: Calculate along arc
return false;
// 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 )

View File

@ -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

View File

@ -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;

View File

@ -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 );

View File

@ -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() ) );
}
}

View File

@ -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,17 +238,29 @@ CN_ITEM* CN_LIST::Add( D_PAD* pad )
return item;
}
CN_ITEM* CN_LIST::Add( TRACK* track )
{
auto item = new CN_ITEM( track, true );
m_items.push_back( item );
item->AddAnchor( track->GetStart() );
item->AddAnchor( track->GetEnd() );
item->SetLayer( track->GetLayer() );
addItemtoTree( item );
SetDirty();
return item;
}
CN_ITEM* CN_LIST::Add( TRACK* track )
{
auto item = new CN_ITEM( track, true );
m_items.push_back( item );
item->AddAnchor( track->GetStart() );
item->AddAnchor( track->GetEnd() );
item->SetLayer( track->GetLayer() );
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 )
{

View File

@ -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 );

View File

@ -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>

View File

@ -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>

View File

@ -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 );

View File

@ -26,6 +26,7 @@
#include <class_board.h>
#include <class_module.h>
#include <class_track.h>
#include <collectors.h>
#include <reporter.h>

View File

@ -38,6 +38,7 @@
#include <build_version.h>
#include <class_board.h>
#include <class_track.h>
#include <pcbplot.h>
#include <pcbnew.h>

View File

@ -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>

View File

@ -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;

View File

@ -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

View File

@ -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() );

View File

@ -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 );

View File

@ -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:

View File

@ -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

53
pcbnew/router/pns_arc.cpp Normal file
View File

@ -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;
}
}

118
pcbnew/router/pns_arc.h Normal file
View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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:
{
int thresh = Settings().SmoothDraggedSegments() ? m_draggedLine.Width() / 4 : 0;
//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 );

View File

@ -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;
};

View File

@ -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;

View File

@ -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";

View File

@ -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
};

View File

@ -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()

View File

@ -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 );

View File

@ -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 );

View File

@ -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 ),
m_line( aOther.m_line ),
m_width( aOther.m_width )
LINE::LINE( const LINE& aOther )
: ITEM( aOther ),
m_line( aOther.m_line ),
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,22 +497,21 @@ 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 );
int i, j;
int best_dist = INT_MAX;
int i, j;
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];
VECTOR2I snap_p[2];
DIRECTION_45 dragDir( aPath.CSegment( aIndex ) );
int snap_d[2] = { -1, -1 };
int snap_d[2] = { -1, -1 };
if( aThreshold == 0 )
if( m_snapThreshhold == 0 )
return aP;
if( aIndex >= 2 )
@ -566,17 +568,17 @@ 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;
}
VECTOR2I best = aP;
int minDist = INT_MAX;
int minDist = INT_MAX;
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,16 +588,15 @@ 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 );
VECTOR2I target( aP );
SEG guideA[2], guideB[2];
int index = aIndex;
target = snapToNeighbourSegments( path, aP, aIndex, aSnappingThreshold );
target = snapToNeighbourSegments( path, aP, aIndex );
if( index == 0 )
{
@ -608,7 +609,7 @@ void LINE::dragSegment45( const VECTOR2I& aP, int aIndex, int aSnappingThreshold
path.Insert( path.PointCount() - 1, path.CPoint( -1 ) );
}
SEG dragged = path.CSegment( index );
SEG dragged = path.CSegment( index );
DIRECTION_45 drag_dir( dragged );
SEG s_prev = path.CSegment( index - 1 );
@ -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() );
}
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() );
@ -663,32 +654,24 @@ 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() );
}
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() );
guideB[0] = guideB[1] = SEG( dragged.B, dragged.B + dir_next.ToVector() );
}
SEG s_current( target, target + drag_dir.ToVector() );
int best_len = INT_MAX;
int best_len = INT_MAX;
SHAPE_LINE_CHAIN best;
for( int i = 0; i < 2; i++ )
@ -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;

View File

@ -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 ),
m_line( aLine ),
m_width( aBase.m_width )
LINE( const LINE& aBase, const SHAPE_LINE_CHAIN& aLine )
: ITEM( aBase ),
m_line( aLine ),
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;
};

View File

@ -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,17 +1060,32 @@ 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++ )
{
const SEG& s = pl.CSegment( i );
lastSeg = new SEGMENT( s, m_currentNet );
std::unique_ptr< SEGMENT > seg( lastSeg );
seg->SetWidth( pl.Width() );
seg->SetLayer( m_currentLayer );
if( ! m_lastNode->Add( std::move( seg ) ) )
ssize_t arcIndex = l.ArcIndex( i );
if( arcIndex < 0 )
{
const SEG& s = pl.CSegment( i );
auto seg = std::make_unique<SEGMENT>( s, m_currentNet );
seg->SetWidth( pl.Width() );
seg->SetLayer( m_currentLayer );
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;
}
}
@ -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 );

View File

@ -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_ */

View File

@ -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 )
{

View File

@ -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.

View File

@ -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;

View File

@ -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 )

View File

@ -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;

View File

@ -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 ) );
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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( &currentLine, (VIA*) ni );

View File

@ -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 );

View File

@ -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;
}

View File

@ -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() );
@ -180,9 +180,10 @@ 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();
JOINT* jt = m_world->FindJoint( anchor, aLine );
VECTOR2I anchor = aLeft ? aLine->CPoint( 0 ) : aLine->CPoint( -1 );
LINKED_ITEM* last =
aLeft ? aLine->LinkedSegments().front() : aLine->LinkedSegments().back();
JOINT* jt = m_world->FindJoint( anchor, aLine );
assert( jt != NULL );

View File

@ -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 )
{

View File

@ -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 );

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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>

View File

@ -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 )
{

View File

@ -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 = {} );

View File

@ -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>

View File

@ -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:

View File

@ -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;

View File

@ -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>

View File

@ -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
)

View File

@ -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()