← Back to team overview

kicad-developers team mailing list archive

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