7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-18 21:29:17 +00:00

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>

Some files were not shown because too many files have changed in this diff Show More