kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #08444
specctra_export patch to allow nesteted pcb edges
Hi,
recently I had to do a few boards that required some weird cutouts (similar to
the test example in the png).
To allow freerouting to deal with nested board outlines I modified
specctra_export.cpp to emit signal layer keepouts for every inner edge area.
The attached diff file contains the changes made to specctra_export.diff.
It would be helpful if anyone can comment on that modification (maybe I
tweaked too much).
Thanks,
Thomas
Attachment:
keepout_example.png
Description: PNG image
*** /tmp/KIKAD/kicad.bzr/pcbnew/specctra_export.cpp 2012-06-03 00:40:33.468858135 +0200
--- ../../pcbnew/specctra_export.cpp 2012-06-12 20:45:25.894397234 +0200
***************
*** 228,233 ****
--- 228,237 ----
*/
static DRAWSEGMENT* findPoint( const wxPoint& aPoint, TYPE_COLLECTOR* items )
{
+ int mind = 0x7fffffff;
+ int mindi = 0;
+ int d, xa, ya, xe, ye;
+
for( int i=0; i<items->GetCount(); ++i )
{
DRAWSEGMENT* graphic = (DRAWSEGMENT*) (*items)[i];
***************
*** 242,247 ****
--- 246,269 ----
items->Remove(i);
return graphic;
}
+ d = abs(aPoint.x - graphic->GetArcStart().x) + abs(aPoint.y - graphic->GetArcStart().y);
+ if (d < mind){
+ mind = d;
+ mindi = i;
+ xa = graphic->GetArcStart().x;
+ ya = graphic->GetArcStart().y;
+ xe = graphic->GetArcEnd().x;
+ ye = graphic->GetArcEnd().y;
+ }
+ d = abs(aPoint.x - graphic->GetArcEnd().x) + abs(aPoint.y - graphic->GetArcEnd().y);
+ if (d < mind){
+ mind = d;
+ mindi = i;
+ xe = graphic->GetArcStart().x;
+ ye = graphic->GetArcStart().y;
+ xa = graphic->GetArcEnd().x;
+ ya = graphic->GetArcEnd().y;
+ }
break;
default:
***************
*** 250,255 ****
--- 272,340 ----
items->Remove(i);
return graphic;
}
+ d = abs(aPoint.x - graphic->GetStart().x) + abs(aPoint.y - graphic->GetStart().y);
+ if (d < mind){
+ mind = d;
+ mindi = i;
+ xa = graphic->GetStart().x;
+ ya = graphic->GetStart().y;
+ xe = graphic->GetEnd().x;
+ ye = graphic->GetEnd().y;
+ }
+ d = abs(aPoint.x - graphic->GetEnd().x) + abs(aPoint.y - graphic->GetEnd().y);
+ if (d < mind){
+ mind = d;
+ mindi = i;
+ xe = graphic->GetStart().x;
+ ye = graphic->GetStart().y;
+ xa = graphic->GetEnd().x;
+ ya = graphic->GetEnd().y;
+ }
+ }
+ }
+ #ifdef USE_PCBNEW_NANOMETRES
+ #warning "Tweak Edge export by 100 µ"
+ if (mind > 100000) return NULL;
+ #else
+ #warning "Tweak Edge export by 10 mil"
+ if (mind > 100) return NULL;
+ #endif // USE_PCBNEW_NANOMETRES
+ for( int i=0; i<items->GetCount(); ++i )
+ {
+ DRAWSEGMENT* graphic = (DRAWSEGMENT*) (*items)[i];
+
+ wxASSERT( graphic->Type() == PCB_LINE_T );
+
+ switch( graphic->GetShape() )
+ {
+ case S_ARC:
+ d = abs(aPoint.x - graphic->GetArcStart().x) + abs(aPoint.y - graphic->GetArcStart().y);
+ if (d == mind)
+ {
+ items->Remove(i);
+ return graphic;
+ }
+ d = abs(aPoint.x - graphic->GetArcEnd().x) + abs(aPoint.y - graphic->GetArcEnd().y);
+ if (d == mind)
+ {
+ items->Remove(i);
+ return graphic;
+ }
+ break;
+
+ default:
+ d = abs(aPoint.x - graphic->GetStart().x) + abs(aPoint.y - graphic->GetStart().y);
+ if (d == mind)
+ {
+ items->Remove(i);
+ return graphic;
+ }
+ d = abs(aPoint.x - graphic->GetEnd().x) + abs(aPoint.y - graphic->GetEnd().y);
+ if (d == mind)
+ {
+ items->Remove(i);
+ return graphic;
+ }
}
}
***************
*** 804,814 ****
wxPoint prevPt;
! DRAWSEGMENT* graphic = (DRAWSEGMENT*) items[0];
// the first DRAWSEGMENT is in 'graphic*', ok to remove it from 'items'
! items.Remove( 0 );
prevPt = graphic->GetEnd();
path->AppendPoint( mapPt( prevPt ) );
--- 889,994 ----
wxPoint prevPt;
! DRAWSEGMENT* graphic;
!
! // get outer polygon (xmin defines it, assume only "valid" edges
! // find edge point wit minimal x
! // emit this polygon...
! wxPoint xmin = wxPoint(0x7fffffff, 0 );
! int xmini = 0;
! for (int i = 0; i < items.GetCount(); i++)
! {
! graphic = (DRAWSEGMENT*) items[i];
! switch( graphic->GetShape() )
! {
! case S_SEGMENT:
! {
! if (graphic->GetStart().x < xmin.x)
! {
! xmin = graphic->GetStart();
! xmini = i;
! }
! if (graphic->GetEnd().x < xmin.x)
! {
! xmin = graphic->GetEnd();
! xmini = i;
! }
! }
! break;
!
! case S_ARC:
! // freerouter does not yet understand arcs, so approximate
! // an arc with a series of short lines and put those
! // line segments into the !same! PATH.
! {
! const int STEPS = 9; // in an arc of 90 degrees
!
! wxPoint start = graphic->GetArcStart();
! wxPoint end = graphic->GetArcEnd();
! wxPoint center = graphic->GetCenter();
! double angle = -graphic->GetAngle();
!
! wxPoint aPt;
!
! for( int step=1; step<=STEPS; ++step )
! {
! double rotation = ( angle * step )/STEPS;
!
! aPt = start;
!
! RotatePoint( &aPt.x, &aPt.y, center.x, center.y, rotation );
!
! if (aPt.x < xmin.x)
! {
! xmin = aPt;
! xmini = i;
! }
! }
! }
! break;
!
! case S_CIRCLE:
! #if 1
! // do not output a circle, freerouter does not understand it.
! // this might be a mounting hole or something, ignore it without error
! // because some of our demo boards have used the edges pcb layer to
! // hold islanded circles, rather than simply using holes.
! break;
! #else
! // Do not output a circle, freerouter does not understand it.
! // tell user his board has a problem, this is better than silently
! // ignoring the error. "edges pcb" layer should not be used
! // to hold islanded circles which could or should be better done
! // as simple holes. (Some of our demo boards have this problem.)
! // fall thru here to report the error.
! #endif
!
! default:
! {
! wxString error;
!
! error.Printf( _("Unsupported DRAWSEGMENT type %s"),
! GetChars( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() ) ) );
+ ThrowIOError( error );
+ }
+ break;
+ }
+ }
+ // collect all enclosed sub polygons
+ #ifdef USE_PCBNEW_NANOMETRES
+ #warning "Tweak Edge export by 100 µ"
+ #define DLIM 100000
+ #else
+ #warning "Tweak Edge export by 10 mil"
+ #define DLIM 100
+ #endif // USE_PCBNEW_NANOMETRES
+ #define TWEAKER(a,b) ((abs(a.x-b.x)+abs(a.y-b.y)) < DLIM)
// the first DRAWSEGMENT is in 'graphic*', ok to remove it from 'items'
! graphic = (DRAWSEGMENT*) items[xmini];
! items.Remove( xmini );
+ wxPoint startPt = wxPoint(graphic->GetEnd());
prevPt = graphic->GetEnd();
path->AppendPoint( mapPt( prevPt ) );
***************
*** 822,835 ****
{
wxPoint nextPt;
! if( prevPt != graphic->GetStart() )
{
! wxASSERT( prevPt == graphic->GetEnd() );
nextPt = graphic->GetStart();
}
else
{
! wxASSERT( prevPt == graphic->GetStart() );
nextPt = graphic->GetEnd();
}
--- 1001,1014 ----
{
wxPoint nextPt;
! if( !TWEAKER(prevPt, graphic->GetStart()) )
{
! wxASSERT( TWEAKER (prevPt, graphic->GetEnd()) );
nextPt = graphic->GetStart();
}
else
{
! wxASSERT( TWEAKER (prevPt, graphic->GetStart()) );
nextPt = graphic->GetEnd();
}
***************
*** 850,858 ****
wxPoint center = graphic->GetCenter();
double angle = -graphic->GetAngle();
! if( prevPt != start )
{
! wxASSERT( prevPt == graphic->GetArcEnd() );
angle = -angle;
EXCHG( start, end );
--- 1029,1037 ----
wxPoint center = graphic->GetCenter();
double angle = -graphic->GetAngle();
! if( !TWEAKER(prevPt, start) )
{
! wxASSERT( TWEAKER(prevPt, graphic->GetArcEnd()) );
angle = -angle;
EXCHG( start, end );
***************
*** 903,909 ****
break;
}
! if( items.GetCount() == 0 )
break;
graphic = findPoint( prevPt, &items );
--- 1082,1088 ----
break;
}
! if (TWEAKER(startPt, prevPt))
break;
graphic = findPoint( prevPt, &items );
***************
*** 919,924 ****
--- 1098,1248 ----
}
}
+ while( items.GetCount() )
+ {
+ // emit a signal layers keepout for every sub-polygon left...
+ KEEPOUT* keepout = new KEEPOUT( NULL, T_keepout );
+ PATH* keepPol = new PATH( NULL, T_polygon );
+ keepout->SetShape( keepPol );
+ keepPol->SetLayerId( "signal" );
+ pcb->structure->keepouts.push_back( keepout );
+ graphic = (DRAWSEGMENT*) items[0];
+ items.Remove( 0 );
+
+ wxPoint startPt = wxPoint( graphic->GetEnd() );
+ prevPt = graphic->GetEnd();
+ keepPol->AppendPoint( mapPt( prevPt ));
+
+ // do not append the other end point yet, this first 'graphic' might be an arc
+ for(;;)
+ {
+ switch( graphic->GetShape() )
+ {
+ case S_SEGMENT:
+ {
+ wxPoint nextPt;
+
+ if( !TWEAKER(prevPt, graphic->GetStart()) )
+ {
+ wxASSERT( TWEAKER (prevPt, graphic->GetEnd()) );
+ nextPt = graphic->GetStart();
+ }
+ else
+ {
+ wxASSERT( TWEAKER (prevPt, graphic->GetStart()) );
+ nextPt = graphic->GetEnd();
+ }
+
+ prevPt = nextPt;
+ keepPol->AppendPoint( mapPt( prevPt ));
+ }
+ break;
+
+ case S_ARC:
+ // freerouter does not yet understand arcs, so approximate
+ // an arc with a series of short lines and put those
+ // line segments into the !same! PATH.
+ {
+ const int STEPS = 9; // in an arc of 90 degrees
+
+ wxPoint start = graphic->GetArcStart();
+ wxPoint end = graphic->GetArcEnd();
+ wxPoint center = graphic->GetCenter();
+ double angle = -graphic->GetAngle();
+
+ if( !TWEAKER(prevPt, start) )
+ {
+ wxASSERT( TWEAKER(prevPt, graphic->GetArcEnd()) );
+
+ angle = -angle;
+ EXCHG( start, end );
+ }
+
+ wxPoint nextPt;
+
+ for( int step=1; step<=STEPS; ++step )
+ {
+ double rotation = ( angle * step )/STEPS;
+
+ nextPt = start;
+
+ RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
+
+ keepPol->AppendPoint( mapPt( nextPt ));
+ }
+
+ prevPt = nextPt;
+ }
+ break;
+
+ case S_CIRCLE:
+ #if 1
+ // do a circle segmentation
+ {
+ const int STEPS = 9*4; // in an arc of 90 degrees
+
+ wxPoint start;
+ wxPoint center = graphic->GetCenter();
+ int radius = graphic->GetRadius();
+ double angle = 3600.0;
+
+ start = center;
+ start.x += radius;
+
+ wxPoint nextPt;
+
+ for( int step=1; step<=STEPS; ++step )
+ {
+ double rotation = ( angle * step )/STEPS;
+
+ nextPt = start;
+
+ RotatePoint( &nextPt.x, &nextPt.y, center.x, center.y, rotation );
+
+ keepPol->AppendPoint( mapPt( nextPt ));
+ }
+
+ prevPt = startPt;
+ }
+ break;
+ #else
+ // Do not output a circle, freerouter does not understand it.
+ // tell user his board has a problem, this is better than silently
+ // ignoring the error. "edges pcb" layer should not be used
+ // to hold islanded circles which could or should be better done
+ // as simple holes. (Some of our demo boards have this problem.)
+ // fall thru here to report the error.
+ #endif
+
+ default:
+ {
+ wxString error;
+
+ error.Printf( _("Unsupported DRAWSEGMENT type %s"),
+ GetChars( BOARD_ITEM::ShowShape( (STROKE_T) graphic->GetShape() ) ) );
+
+ ThrowIOError( error );
+ }
+ break;
+ }
+
+ if (TWEAKER(startPt, prevPt))
+ break;
+
+ graphic = findPoint( prevPt, &items );
+ if( !graphic )
+ {
+ wxString error;
+
+ error << _("Unable to find the next segment with an endpoint of ");
+ error << prevPt;
+ error << wxChar('\n');
+ error << _("Edit Edges_Pcb segments, making them contiguous.");
+ ThrowIOError( error );
+ }
+ }
+ }
+
#if 0 && defined(DEBUG)
STRING_FORMATTER sf;
path->Format( &sf, 0 );
Follow ups