router: support for non-90 degree pad orientations

This commit is contained in:
Mathias Grimmberger 2015-07-02 16:09:43 +02:00 committed by Maciej Suminski
parent 4abcc159d2
commit 7724c581fd
11 changed files with 410 additions and 33 deletions

View File

@ -30,6 +30,7 @@
#include <geometry/shape_circle.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_convex.h>
typedef VECTOR2I::extended_type ecoord;
@ -165,6 +166,32 @@ static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_LINE_CHAIN& aB,
}
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_CONVEX& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
bool found;
const SHAPE_LINE_CHAIN& lc( aB.Vertices() );
found = lc.Distance( aA.GetCenter() ) <= aClearance + aA.GetRadius();
if( !aNeedMTV || !found )
return found;
SHAPE_CIRCLE cmoved( aA );
VECTOR2I f_total( 0, 0 );
for( int s = 0; s < lc.SegmentCount(); s++ )
{
VECTOR2I f = pushoutForce( cmoved, lc.CSegment( s ), aClearance );
cmoved.SetCenter( cmoved.GetCenter() + f );
f_total += f;
}
aMTV = f_total;
return found;
}
static inline bool Collide( const SHAPE_CIRCLE& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
@ -189,6 +216,20 @@ static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_LINE_CHAIN&
}
static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_CONVEX& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
return Collide( aA, aB.Vertices(), aClearance, aNeedMTV, aMTV );
}
static inline bool Collide( const SHAPE_CONVEX& aA, const SHAPE_CONVEX& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
return Collide( aA.Vertices(), aB.Vertices(), aClearance, aNeedMTV, aMTV );
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
@ -204,6 +245,13 @@ static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_LINE_CHAIN& aB, in
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_CONVEX& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
return Collide( aA, aB.Vertices(), aClearance, aNeedMTV, aMTV );
}
static inline bool Collide( const SHAPE_RECT& aA, const SHAPE_SEGMENT& aSeg, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
@ -228,6 +276,13 @@ static inline bool Collide( const SHAPE_LINE_CHAIN& aA, const SHAPE_SEGMENT& aB,
}
static inline bool Collide( const SHAPE_CONVEX& aA, const SHAPE_SEGMENT& aB, int aClearance,
bool aNeedMTV, VECTOR2I& aMTV )
{
return Collide( aA.Vertices(), aB, aClearance, aNeedMTV, aMTV );
}
template<class ShapeAType, class ShapeBType>
inline bool CollCase( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeedMTV, VECTOR2I& aMTV )
{
@ -264,6 +319,9 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
case SH_SEGMENT:
return CollCase<SHAPE_RECT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
case SH_CONVEX:
return CollCase<SHAPE_RECT, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
default:
break;
}
@ -283,6 +341,9 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
case SH_SEGMENT:
return CollCase<SHAPE_CIRCLE, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
case SH_CONVEX:
return CollCase<SHAPE_CIRCLE, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
default:
break;
}
@ -302,6 +363,9 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
case SH_SEGMENT:
return CollCase<SHAPE_LINE_CHAIN, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
case SH_CONVEX:
return CollCase<SHAPE_LINE_CHAIN, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
default:
break;
}
@ -321,6 +385,31 @@ bool CollideShapes( const SHAPE* aA, const SHAPE* aB, int aClearance, bool aNeed
case SH_SEGMENT:
return CollCase<SHAPE_SEGMENT, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
case SH_CONVEX:
return CollCase<SHAPE_CONVEX, SHAPE_SEGMENT>( aB, aA, aClearance, aNeedMTV, aMTV );
default:
break;
}
case SH_CONVEX:
switch( aB->Type() )
{
case SH_RECT:
return CollCase<SHAPE_RECT, SHAPE_CONVEX>( aB, aA, aClearance, aNeedMTV, aMTV );
case SH_CIRCLE:
return CollCase<SHAPE_CIRCLE, SHAPE_CONVEX>( aB, aA, aClearance, aNeedMTV, aMTV );
case SH_LINE_CHAIN:
return CollCase<SHAPE_LINE_CHAIN, SHAPE_CONVEX>( aB, aA, aClearance, aNeedMTV, aMTV );
case SH_SEGMENT:
return CollCase<SHAPE_CONVEX, SHAPE_SEGMENT>( aA, aB, aClearance, aNeedMTV, aMTV );
case SH_CONVEX:
return CollCase<SHAPE_CONVEX, SHAPE_CONVEX>( aA, aB, aClearance, aNeedMTV, aMTV );
default:
break;
}

View File

@ -499,6 +499,26 @@ const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const VECTOR2I& aP ) const
}
const VECTOR2I SHAPE_LINE_CHAIN::NearestPoint( const SEG& aSeg, int& dist ) const
{
int nearest = 0;
dist = INT_MAX;
for( int i = 0; i < PointCount(); i++ )
{
int d = aSeg.LineDistance( CPoint( i ) );
if( d < dist )
{
dist = d;
nearest = i;
}
}
return CPoint( nearest );
}
const std::string SHAPE_LINE_CHAIN::Format() const
{
std::stringstream ss;

View File

@ -264,6 +264,9 @@ public:
BOX2I bbox;
bbox.Compute( m_points );
if( aClearance != 0 )
bbox.Inflate( aClearance );
return bbox;
}
@ -535,6 +538,17 @@ public:
*/
const VECTOR2I NearestPoint( const VECTOR2I& aP ) const;
/**
* Function NearestPoint()
*
* Finds a point on the line chain that is closest to the line defined
* by the points of segment aSeg, also returns the distance.
* @param aSeg Segment defining the line.
* @param dist reference receiving the distance to the nearest point.
* @return the nearest point.
*/
const VECTOR2I NearestPoint( const SEG& aSeg, int& dist ) const;
/// @copydoc SHAPE::Format()
const std::string Format() const;

View File

@ -29,6 +29,7 @@
#include <geometry/shape_line_chain.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_circle.h>
#include <geometry/shape_convex.h>
PNS_LOGGER::PNS_LOGGER( )
{
@ -173,6 +174,17 @@ void PNS_LOGGER::dumpShape( const SHAPE* aSh )
break;
}
case SH_CONVEX:
{
const SHAPE_CONVEX* c = (const SHAPE_CONVEX*) aSh;
m_theLog << "convex " << c->PointCount() << " ";
for( int i = 0; i < c->PointCount(); i++ )
m_theLog << c->CPoint( i ).x << " " << c->CPoint( i ).y << " ";
break;
}
default:
break;
}

View File

@ -22,6 +22,7 @@
#include <geometry/shape_line_chain.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_convex.h>
#include "pns_line.h"
#include "pns_diff_pair.h"
@ -659,6 +660,48 @@ PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::circleBreakouts( int aWidth,
}
PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::convexBreakouts( int aWidth,
const SHAPE* aShape, bool aPermitDiagonal ) const
{
BREAKOUT_LIST breakouts;
const SHAPE_CONVEX* convex = static_cast<const SHAPE_CONVEX*>( aShape );
BOX2I bbox = convex->BBox( 0 );
VECTOR2I p0 = bbox.Centre();
// must be large enough to guarantee intersecting the convex polygon
int length = bbox.GetSize().EuclideanNorm() / 2 + 5;
for( int angle = 0; angle < 360; angle += ( aPermitDiagonal ? 45 : 90 ) )
{
SHAPE_LINE_CHAIN l;
VECTOR2I v0( p0 + VECTOR2I( length, 0 ).Rotate( angle * M_PI / 180.0 ) );
SHAPE_LINE_CHAIN::INTERSECTIONS intersections;
int n = convex->Vertices().Intersect( SEG( p0, v0 ), intersections );
// if n == 1 intersected a segment
// if n == 2 intersected the common point of 2 segments
// n == 0 can not happen I think, but...
if( n > 0 )
{
l.Append( p0 );
// for a breakout distance relative to the distance between
// center and polygon edge
//l.Append( intersections[0].p + (v0 - p0).Resize( (intersections[0].p - p0).EuclideanNorm() * 0.4 ) );
// for an absolute breakout distance, e.g. 0.1 mm
l.Append( intersections[0].p + (v0 - p0).Resize( 100000 ) );
// for the breakout right on the polygon edge
//l.Append( intersections[0].p );
breakouts.push_back( l );
}
}
return breakouts;
}
PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::rectBreakouts( int aWidth,
const SHAPE* aShape, bool aPermitDiagonal ) const
{
@ -743,6 +786,9 @@ PNS_OPTIMIZER::BREAKOUT_LIST PNS_OPTIMIZER::computeBreakouts( int aWidth,
case SH_CIRCLE:
return circleBreakouts( aWidth, shape, aPermitDiagonal );
case SH_CONVEX:
return convexBreakouts( aWidth, shape, aPermitDiagonal );
default:
break;
}

View File

@ -158,6 +158,7 @@ private:
BREAKOUT_LIST circleBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
BREAKOUT_LIST rectBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
BREAKOUT_LIST ovalBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
BREAKOUT_LIST convexBreakouts( int aWidth, const SHAPE* aShape, bool aPermitDiagonal ) const;
BREAKOUT_LIST computeBreakouts( int aWidth, const PNS_ITEM* aItem, bool aPermitDiagonal ) const;
int smartPadsSingle( PNS_LINE* aLine, PNS_ITEM* aPad, bool aEnd, int aEndVertex );

View File

@ -207,53 +207,137 @@ PNS_ITEM* PNS_ROUTER::syncPad( D_PAD* aPad )
double orient = aPad->GetOrientation() / 10.0;
bool nonOrtho = false;
if( orient == 90.0 || orient == 270.0 )
sz = VECTOR2I( sz.y, sz.x );
else if( orient != 0.0 && orient != 180.0 )
if( aPad->GetShape() == PAD_CIRCLE )
{
// rotated pads are replaced by for the moment by circles due to my laziness ;)
solid->SetShape( new SHAPE_CIRCLE( c, std::min( sz.x, sz.y ) / 2 ) );
nonOrtho = true;
}
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
} else {
if( !nonOrtho )
{
switch( aPad->GetShape() )
if( orient == 0.0 || orient == 90.0 || orient == 180.0 || orient == 270.0 )
{
case PAD_CIRCLE:
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
break;
if( orient == 90.0 || orient == 270.0 )
sz = VECTOR2I( sz.y, sz.x );
case PAD_OVAL:
if( sz.x == sz.y )
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
else
switch( aPad->GetShape() )
{
VECTOR2I delta;
if( sz.x > sz.y )
delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 );
case PAD_OVAL:
if( sz.x == sz.y )
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
else
delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 );
{
VECTOR2I delta;
if( sz.x > sz.y )
delta = VECTOR2I( ( sz.x - sz.y ) / 2, 0 );
else
delta = VECTOR2I( 0, ( sz.y - sz.x ) / 2 );
SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta,
std::min( sz.x, sz.y ) );
solid->SetShape( shape );
}
break;
case PAD_RECT:
solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
break;
case PAD_TRAPEZOID:
{
wxPoint coords[4];
aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
SHAPE_CONVEX* shape = new SHAPE_CONVEX();
for( int ii = 0; ii < 4; ii++ )
{
shape->Append( wx_c + coords[ii] );
}
SHAPE_SEGMENT* shape = new SHAPE_SEGMENT( c - delta, c + delta,
std::min( sz.x, sz.y ) );
solid->SetShape( shape );
break;
}
break;
case PAD_RECT:
solid->SetShape( new SHAPE_RECT( c - sz / 2, sz.x, sz.y ) );
break;
default:
TRACEn( 0, "unsupported pad shape" );
delete solid;
return NULL;
}
} else {
switch( aPad->GetShape() )
{
// PAD_CIRCLE already handled above
default:
TRACEn( 0, "unsupported pad shape" );
delete solid;
case PAD_OVAL:
if( sz.x == sz.y )
solid->SetShape( new SHAPE_CIRCLE( c, sz.x / 2 ) );
else
{
wxPoint start;
wxPoint end;
wxPoint corner;
return NULL;
SHAPE_CONVEX* shape = new SHAPE_CONVEX();
int w = aPad->BuildSegmentFromOvalShape( start, end, 0.0, wxSize( 0, 0 ) );
if( start.y == 0 )
corner = wxPoint( start.x, -(w / 2) );
else
corner = wxPoint( w / 2, start.y );
RotatePoint( &start, aPad->GetOrientation() );
RotatePoint( &corner, aPad->GetOrientation() );
shape->Append( wx_c + corner );
for( int rot = 100; rot <= 1800; rot += 100 )
{
wxPoint p( corner );
RotatePoint( &p, start, rot );
shape->Append( wx_c + p );
}
if( end.y == 0 )
corner = wxPoint( end.x, w / 2 );
else
corner = wxPoint( -(w / 2), end.y );
RotatePoint( &end, aPad->GetOrientation() );
RotatePoint( &corner, aPad->GetOrientation() );
shape->Append( wx_c + corner );
for( int rot = 100; rot <= 1800; rot += 100 )
{
wxPoint p( corner );
RotatePoint( &p, end, rot );
shape->Append( wx_c + p );
}
solid->SetShape( shape );
}
break;
case PAD_RECT:
case PAD_TRAPEZOID:
{
wxPoint coords[4];
aPad->BuildPadPolygon( coords, wxSize( 0, 0 ), aPad->GetOrientation() );
SHAPE_CONVEX* shape = new SHAPE_CONVEX();
for( int ii = 0; ii < 4; ii++ )
{
shape->Append( wx_c + coords[ii] );
}
solid->SetShape( shape );
break;
}
default:
TRACEn( 0, "unsupported pad shape" );
delete solid;
return NULL;
}
}
}
return solid;
}

View File

@ -24,6 +24,7 @@
#include <geometry/shape_line_chain.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_circle.h>
#include <geometry/shape_convex.h>
#include "pns_solid.h"
#include "pns_utils.h"
@ -54,6 +55,13 @@ const SHAPE_LINE_CHAIN PNS_SOLID::Hull( int aClearance, int aWalkaroundThickness
return SegmentHull( *seg, aClearance, aWalkaroundThickness );
}
case SH_CONVEX:
{
SHAPE_CONVEX* convex = static_cast<SHAPE_CONVEX*>( m_shape );
return ConvexHull( *convex, cl );
}
default:
break;
}

View File

@ -81,6 +81,74 @@ const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance,
}
static void MoveDiagonal( SEG& diagonal, const SHAPE_LINE_CHAIN& vertices, int clearance )
{
int dist;
vertices.NearestPoint( diagonal, dist );
dist -= HULL_MARGIN;
VECTOR2I moveBy = (diagonal.A - diagonal.B).Perpendicular().Resize( dist - clearance );
diagonal.A += moveBy;
diagonal.B += moveBy;
}
const SHAPE_LINE_CHAIN ConvexHull( const SHAPE_CONVEX& convex, int clearance )
{
// this defines the horizontal and vertical lines in the hull octagon
BOX2I box = convex.BBox( clearance + HULL_MARGIN );
box.Normalize();
SEG topline = SEG( VECTOR2I( box.GetX(), box.GetY() + box.GetHeight() ),
VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() + box.GetHeight() ) );
SEG rightline = SEG( VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() + box.GetHeight() ),
VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() ) );
SEG bottomline = SEG( VECTOR2I( box.GetX() + box.GetWidth(), box.GetY() ),
box.GetOrigin() );
SEG leftline = SEG( box.GetOrigin(), VECTOR2I( box.GetX(), box.GetY() + box.GetHeight() ) );
const SHAPE_LINE_CHAIN& vertices = convex.Vertices();
// top right diagonal
VECTOR2I corner = box.GetOrigin() + box.GetSize();
SEG toprightline = SEG( corner,
corner + VECTOR2I( box.GetHeight(), -box.GetHeight() ) );
MoveDiagonal( toprightline, vertices, clearance );
// bottom right diagonal
corner = box.GetOrigin() + VECTOR2I( box.GetWidth(), 0 );
SEG bottomrightline = SEG( corner + VECTOR2I( box.GetHeight(), box.GetHeight() ),
corner );
MoveDiagonal( bottomrightline, vertices, clearance );
// bottom left diagonal
corner = box.GetOrigin();
SEG bottomleftline = SEG( corner,
corner + VECTOR2I( -box.GetHeight(), box.GetHeight() ) );
MoveDiagonal( bottomleftline, vertices, clearance );
// top left diagonal
corner = box.GetOrigin() + VECTOR2I( 0, box.GetHeight() );
SEG topleftline = SEG( corner + VECTOR2I( -box.GetHeight(), -box.GetHeight() ),
corner );
MoveDiagonal( topleftline, vertices, clearance );
SHAPE_LINE_CHAIN octagon;
octagon.SetClosed( true );
octagon.Append( leftline.IntersectLines( bottomleftline ).get() );
octagon.Append( bottomline.IntersectLines( bottomleftline ).get() );
octagon.Append( bottomline.IntersectLines( bottomrightline ).get() );
octagon.Append( rightline.IntersectLines( bottomrightline ).get() );
octagon.Append( rightline.IntersectLines( toprightline ).get() );
octagon.Append( topline.IntersectLines( toprightline ).get() );
octagon.Append( topline.IntersectLines( topleftline ).get() );
octagon.Append( leftline.IntersectLines( topleftline ).get() );
return octagon;
}
SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg )
{
SHAPE_RECT r;

View File

@ -26,6 +26,7 @@
#include <geometry/shape_line_chain.h>
#include <geometry/shape_segment.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_convex.h>
#define HULL_MARGIN 10
@ -39,6 +40,16 @@ const SHAPE_LINE_CHAIN OctagonalHull( const VECTOR2I& aP0, const VECTOR2I& aSize
const SHAPE_LINE_CHAIN SegmentHull ( const SHAPE_SEGMENT& aSeg, int aClearance,
int aWalkaroundThickness );
/**
* Function ConvexHull()
*
* Creates an octagonal hull around a convex polygon.
* @param convex The convex polygon.
* @param clearance The minimum distance between polygon and hull.
* @return A closed line chain describing the octagon.
*/
const SHAPE_LINE_CHAIN ConvexHull( const SHAPE_CONVEX& convex, int clearance );
SHAPE_RECT ApproximateSegmentAsRect( const SHAPE_SEGMENT& aSeg );
void DrawDebugPoint( VECTOR2I aP, int aColor );

View File

@ -18,9 +18,11 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <deque>
#include <gal/color4d.h>
#include <geometry/shape_rect.h>
#include <geometry/shape_convex.h>
#include "class_track.h"
#include <pcb_painter.h>
@ -233,7 +235,29 @@ void ROUTER_PREVIEW_ITEM::ViewDraw( int aLayer, KIGFX::GAL* aGal ) const
break;
}
case SH_CONVEX:
case SH_CONVEX:
{
const SHAPE_CONVEX* c = (const SHAPE_CONVEX*) m_shape;
std::deque<VECTOR2D> polygon = std::deque<VECTOR2D>();
for( int i = 0; i < c->PointCount(); i++ )
{
polygon.push_back( c->CDPoint( i ) );
}
aGal->DrawPolygon( polygon );
if( m_clearance > 0 )
{
aGal->SetLayerDepth( ClearanceOverlayDepth );
aGal->SetStrokeColor( COLOR4D( DARKDARKGRAY ) );
aGal->SetIsStroke( true );
aGal->SetLineWidth( 2 * m_clearance );
// need the implicit last segment to be explicit for DrawPolyline
polygon.push_back( c->CDPoint( 0 ) );
aGal->DrawPolyline( polygon );
}
break;
}
case SH_POLY_SET:
case SH_COMPOUND:
break; // Not yet in use