Commit b9f9d539 authored by dickelbeck's avatar dickelbeck

more amazing free specctra software

parent 4a0b5607
...@@ -5,6 +5,21 @@ Started 2007-June-11 ...@@ -5,6 +5,21 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with Please add newer entries at the top, list the date and your name with
email address. email address.
2008-Jan-29 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
+pcbnew:
SPECCTRA export now exports pads with offset OK, exports oval pads OK,
and tries to do less with pcb edges that are not a connected set of lines,
putting the burden back on the PCBNEW user to have clean perimeter lines.
Discovered that freerouter does not support oval pads yet, asked
for enhancement. Discovered a small problem if you modify a PAD in
the MODULE editor but do not replicate that change throughout all module
instances in the board. Is on my @todo list. Otherwise it is getting pretty
good now. Most boards load into freerouter, except mine, which if exported
with part numbers, hangs the freerouter! I may be away for a few days doing
billable work, after which I will begin the 2 imports, *.dsn and *.ses.
2008-Jan-31 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr> 2008-Jan-31 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================ ================================================================================
+pcbnew: +pcbnew:
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
Wide use is made of boost::ptr_vector<> and std::vector<> template classes. Wide use is made of boost::ptr_vector<> and std::vector<> template classes.
If the contained object is small, then std::vector tends to be used. If the contained object is small, then std::vector tends to be used.
If the contained object is large, variable size, or would require writing If the contained object is large, variable size, or would require writing
an assignment operator() or copy constructore, then boost::ptr_vector an assignment operator() or copy constructor, then boost::ptr_vector
cannot be beat. cannot be beat.
*/ */
......
...@@ -695,19 +695,19 @@ public: ...@@ -695,19 +695,19 @@ public:
const char* quote = out->GetQuoteChar( layer_id.c_str() ); const char* quote = out->GetQuoteChar( layer_id.c_str() );
const int RIGHTMARGIN = 80; const int RIGHTMARGIN = 70;
int perLine = out->Print( nestLevel, "(%s %s%s%s %.6g", int perLine = out->Print( nestLevel, "(%s %s%s%s %.6g",
LEXER::GetTokenText( Type() ), LEXER::GetTokenText( Type() ),
quote, layer_id.c_str(), quote, quote, layer_id.c_str(), quote,
aperture_width ); aperture_width );
int wrapNest = MAX( nestLevel+1, 6 );
for( unsigned i=0; i<points.size(); ++i ) for( unsigned i=0; i<points.size(); ++i )
{ {
if( perLine > RIGHTMARGIN ) if( perLine > RIGHTMARGIN )
{ {
out->Print( 0, "\n" ); out->Print( 0, "\n" );
perLine = out->Print( nestLevel+1, "%s", "" ); perLine = out->Print( wrapNest, "%s", "" );
newline = "\n";
} }
else else
perLine += out->Print( 0, " " ); perLine += out->Print( 0, " " );
...@@ -717,11 +717,10 @@ public: ...@@ -717,11 +717,10 @@ public:
if( aperture_type == T_square ) if( aperture_type == T_square )
{ {
out->Print( 0, "\n" ); out->Print( 0, "(aperture_type square)" );
out->Print( nestLevel+1, "(aperture_type square))\n" );
} }
else
out->Print( 0, ")%s", newline ); out->Print( 0, ")%s", newline );
} }
}; };
typedef boost::ptr_vector<PATH> PATHS; typedef boost::ptr_vector<PATH> PATHS;
......
...@@ -73,6 +73,9 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event ) ...@@ -73,6 +73,9 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
SPECCTRA_DB db; SPECCTRA_DB db;
bool ok = true; bool ok = true;
wxString errorText; wxString errorText;
BASE_SCREEN* screen = GetScreen();
bool wasModified = screen->IsModify() && !screen->IsSave();
db.SetPCB( SPECCTRA_DB::MakePCB() ); db.SetPCB( SPECCTRA_DB::MakePCB() );
...@@ -92,6 +95,12 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event ) ...@@ -92,6 +95,12 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
errorText = ioe.errorText; errorText = ioe.errorText;
} }
// The two calls below to BOARD::Change_Side_Module(), both set the
// modified flag, yet their actions cancel each other out, so it should
// be ok to clear the modify flag.
if( !wasModified )
screen->ClrModify();
if( ok ) if( ok )
{ {
// @todo display a message saying the export is complete. // @todo display a message saying the export is complete.
...@@ -105,8 +114,8 @@ namespace DSN { ...@@ -105,8 +114,8 @@ namespace DSN {
struct POINT_PAIR struct POINT_PAIR
{ {
POINT p1; ///< start POINT start;
POINT p2; ///< end POINT end;
BOARD_ITEM* item; ///< the item which has these points, TRACK or DRAWSEGMENT BOARD_ITEM* item; ///< the item which has these points, TRACK or DRAWSEGMENT
}; };
typedef std::vector<POINT_PAIR> POINT_PAIRS; typedef std::vector<POINT_PAIR> POINT_PAIRS;
...@@ -114,9 +123,9 @@ typedef std::vector<POINT_PAIR> POINT_PAIRS; ...@@ -114,9 +123,9 @@ typedef std::vector<POINT_PAIR> POINT_PAIRS;
static inline void swap( POINT_PAIR& pair ) static inline void swap( POINT_PAIR& pair )
{ {
POINT temp = pair.p1; POINT temp = pair.start;
pair.p1 = pair.p2; pair.start = pair.end;
pair.p2 = temp; pair.end = temp;
} }
...@@ -157,6 +166,31 @@ static POINT mapPt( const wxPoint& pt ) ...@@ -157,6 +166,31 @@ static POINT mapPt( const wxPoint& pt )
} }
/**
* Function findPOINT
* searches the list of POINT_PAIRS for a matching end to the given POINT.
* @return int - 0 if no match, or + one based index of a POINT_PAIR with a matching ".start",
* or a - one based index of a POINT_PAIR with a matching ".end".
*/
static int findPOINT( const POINT& pt, const POINT_PAIR source[], int count )
{
for( int i=0; i<count; ++i )
{
if( pt == source[i].start )
{
return +( i + 1 );
}
if( pt == source[i].end )
{
return -( i + 1 );
}
}
return 0;
}
/** /**
* Function swapEnds * Function swapEnds
* will swap ends of any POINT_PAIR in the POINT_PAIRS list in order to * will swap ends of any POINT_PAIR in the POINT_PAIRS list in order to
...@@ -164,23 +198,46 @@ static POINT mapPt( const wxPoint& pt ) ...@@ -164,23 +198,46 @@ static POINT mapPt( const wxPoint& pt )
*/ */
static void swapEnds( POINT_PAIRS& aList ) static void swapEnds( POINT_PAIRS& aList )
{ {
POINT temp; if( !aList.size() )
if( aList.size() <= 1 )
return; return;
for( unsigned i=0; i<aList.size(); ++i ) // do an extraction sort based on matching ends here.
POINT_PAIRS sorted;
POINT_PAIRS source( aList );
// try and start the search using a POINT which has at least one match elsewhere.
if( findPOINT( source.begin()->start, &source[1], source.size()-1 ) != 0 )
swap( *source.begin() ); // swap start and end of first PAIR
while( source.size() )
{ {
if( aList[i].p1 == aList[i+1].p1 ) sorted.push_back( *source.begin() );
swap( aList[i] ); source.erase( source.begin() );
else if( aList[i].p1 == aList[i+1].p2 ) // keep looping through the source list looking for a match to the end of the last sorted.
int result;
while( (result = findPOINT( sorted.back().end, &source[0], source.size() ) ) != 0 )
{ {
swap( aList[i] ); int ndx = ABS(result)-1;
swap( aList[i+1] ); sorted.push_back( source[ ndx ] );
++i; // skip next one, we swapped i+1 here source.erase( source.begin()+ndx );
if( result < 0 )
swap( sorted.back() );
} }
} }
#if 1 && defined(DEBUG)
printf( "swapEnds():\n" );
for( unsigned i=0; i<sorted.size(); ++i )
{
printf( "(%.6g,%.6g) (%.6g,%.6g)\n",
sorted[i].start.x, sorted[i].start.y,
sorted[i].end.x, sorted[i].end.y );
}
#endif
aList = sorted;
} }
...@@ -197,15 +254,15 @@ static bool isRectangle( POINT_PAIRS& aList ) ...@@ -197,15 +254,15 @@ static bool isRectangle( POINT_PAIRS& aList )
for( unsigned i=0; i<aList.size(); ++i ) for( unsigned i=0; i<aList.size(); ++i )
{ {
if( i < aList.size()-1 ) if( i < aList.size()-1 )
if( aList[i].p2 != aList[i+1].p1 ) if( aList[i].end != aList[i+1].start )
return false; return false;
if( aList[i].p1.x != aList[i].p2.x if( aList[i].start.x != aList[i].end.x
&& aList[i].p1.y != aList[i].p2.y ) && aList[i].start.y != aList[i].end.y )
return false; return false;
} }
return ( aList[0].p1 == aList[3].p2 ); return ( aList[0].start == aList[3].end );
} }
return false; return false;
} }
...@@ -316,7 +373,11 @@ IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule ) ...@@ -316,7 +373,11 @@ IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule )
pin->padstack_id = padstack->padstack_id; pin->padstack_id = padstack->padstack_id;
pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() ); pin->pin_id = CONV_TO_UTF8( pad->ReturnStringPadName() );
pin->SetVertex( mapPt( pad->m_Pos0 ) );
// copper shape's position is hole position + offset
wxPoint pos = pad->m_Pos0 + pad->m_Offset;
pin->SetVertex( mapPt( pos ) );
} }
} }
...@@ -421,14 +482,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) ...@@ -421,14 +482,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
// padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks // padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
pad->m_logical_connexion = pcb->library->padstacks.size()-1; pad->m_logical_connexion = pcb->library->padstacks.size()-1;
// paddOfset is the offset of copper shape relative to hole position,
// and pad->m_Pos is hole position. All shapes must be shifted by
// this distance, normally (0,0).
// Note that the y correction here is set negative.
POINT padOffset( scale(pad->m_Offset.x), -scale(pad->m_Offset.y) );
// For now, we will report only one layer for the pads. SMD pads are reported on the // For now, we will report only one layer for the pads. SMD pads are reported on the
// top layer, and through hole are reported on <reserved_layer_name> "signal". // top layer, and through hole are reported on <reserved_layer_name> "signal".
// We could do better if there was actually a "layer type" field within // We could do better if there was actually a "layer type" field within
...@@ -462,7 +515,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) ...@@ -462,7 +515,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
circle->SetLayerId( layerName ); circle->SetLayerId( layerName );
circle->SetDiameter( diameter ); circle->SetDiameter( diameter );
circle->SetVertex( padOffset );
++coppers; ++coppers;
} }
} }
...@@ -486,9 +538,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) ...@@ -486,9 +538,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
POINT lowerLeft( -dx, -dy ); POINT lowerLeft( -dx, -dy );
POINT upperRight( dx, dy ); POINT upperRight( dx, dy );
lowerLeft += padOffset;
upperRight += padOffset;
for( int layer=0; layer<reportedLayers; ++layer ) for( int layer=0; layer<reportedLayers; ++layer )
{ {
if( doLayer[layer] ) if( doLayer[layer] )
...@@ -540,38 +589,55 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) ...@@ -540,38 +589,55 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
path = makePath( path = makePath(
POINT( -dr + padOffset.x, padOffset.y - radius ), // aStart POINT( -dr, -radius ), // aStart
POINT( dr + padOffset.x, padOffset.y - radius ), // aEnd POINT( dr, -radius ), // aEnd
layerName ); layerName );
shape->SetShape( path ); shape->SetShape( path );
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
qarc = makeArc( qarc = makeArc(
POINT( dr + padOffset.x, padOffset.y - radius), // aStart POINT( dr, -radius), // aStart
POINT( dr + padOffset.x, padOffset.y + radius), // aEnd POINT( dr, 0.0 ), // aEnd
POINT( dr + padOffset.x, padOffset.y ), // aCenter POINT( dr, 0.0 ), // aCenter
layerName );
shape->SetShape( qarc );
shape = new SHAPE( padstack );
padstack->Append( shape );
qarc = makeArc(
POINT( dr, 0.0), // aStart
POINT( dr, radius), // aEnd
POINT( dr, 0.0 ), // aCenter
layerName ); layerName );
shape->SetShape( qarc ); shape->SetShape( qarc );
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
path = makePath( path = makePath(
POINT( dr + padOffset.x, padOffset.y + radius ), // aStart POINT( dr, radius ), // aStart
POINT( -dr + padOffset.x, padOffset.y + radius ), // aEnd POINT( -dr, radius ), // aEnd
layerName ); layerName );
shape->SetShape( path ); shape->SetShape( path );
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
qarc = makeArc( qarc = makeArc(
POINT( -dr + padOffset.x, padOffset.y + radius), // aStart POINT( -dr, radius), // aStart
POINT( -dr + padOffset.x, padOffset.y - radius), // aEnd POINT( -dr, 0.0), // aEnd
POINT( -dr + padOffset.x, padOffset.y ), // aCenter POINT( -dr, 0.0 ), // aCenter
layerName ); layerName );
shape->SetShape( qarc ); shape->SetShape( qarc );
shape = new SHAPE( padstack );
padstack->Append( shape );
qarc = makeArc(
POINT( -dr, 0.0), // aStart
POINT( -dr, -radius), // aEnd
POINT( -dr, 0.0 ), // aCenter
layerName );
shape->SetShape( qarc );
++coppers; ++coppers;
} }
} }
...@@ -595,38 +661,55 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads ) ...@@ -595,38 +661,55 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
path = makePath( path = makePath(
POINT( -radius + padOffset.x, padOffset.y - dr ), // aStart POINT( -radius, -dr ), // aStart
POINT( -radius + padOffset.x, padOffset.y + dr ), // aEnd POINT( -radius, dr ), // aEnd
layerName ); layerName );
shape->SetShape( path ); shape->SetShape( path );
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
qarc = makeArc( qarc = makeArc(
POINT( -radius + padOffset.x, padOffset.y + dr ), // aStart POINT( -radius, dr ), // aStart
POINT( radius + padOffset.x, padOffset.y + dr), // aEnd POINT( 0.0, dy ), // aEnd
POINT( padOffset.x, padOffset.y +dr ), // aCenter POINT( 0.0, dr ), // aCenter
layerName );
shape->SetShape( qarc );
shape = new SHAPE( padstack );
padstack->Append( shape );
qarc = makeArc(
POINT( 0.0, dy ), // aStart
POINT( radius, dr), // aEnd
POINT( 0.0, dr ), // aCenter
layerName ); layerName );
shape->SetShape( qarc ); shape->SetShape( qarc );
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
path = makePath( path = makePath(
POINT( radius + padOffset.x, padOffset.y + dr ), // aStart POINT( radius, dr ), // aStart
POINT( radius + padOffset.x, padOffset.y - dr ), // aEnd POINT( radius, -dr ), // aEnd
layerName ); layerName );
shape->SetShape( path ); shape->SetShape( path );
shape = new SHAPE( padstack ); shape = new SHAPE( padstack );
padstack->Append( shape ); padstack->Append( shape );
// @todo: this 1/2 circle arc needs to be split into two quarter circle arcs
qarc = makeArc( qarc = makeArc(
POINT( radius + padOffset.x, padOffset.y - dr), // aStart POINT( radius, -dr ), // aStart
POINT( -radius + padOffset.x, padOffset.y - dr), // aEnd POINT( 0.0, -dy ), // aEnd
POINT( padOffset.x, padOffset.y - dr ), // aCenter POINT( 0.0, -dr ), // aCenter
layerName ); layerName );
shape->SetShape( qarc ); shape->SetShape( qarc );
shape = new SHAPE( padstack );
padstack->Append( shape );
qarc = makeArc(
POINT( 0.0, -dy ), // aStart
POINT( -radius, -dr ), // aEnd
POINT( 0.0, -dr ), // aCenter
layerName );
shape->SetShape( qarc );
++coppers; ++coppers;
} }
} }
...@@ -774,8 +857,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -774,8 +857,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
if( item->GetLayer() == EDGE_N ) if( item->GetLayer() == EDGE_N )
{ {
pair.p1 = mapPt( item->m_Start ); pair.start = mapPt( item->m_Start );
pair.p2 = mapPt( item->m_End ); pair.end = mapPt( item->m_End );
pair.item = item; pair.item = item;
ppairs.push_back( pair ); ppairs.push_back( pair );
haveEdges = true; haveEdges = true;
...@@ -802,12 +885,14 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -802,12 +885,14 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
rect->layer_id = "pcb"; rect->layer_id = "pcb";
// opposite corners // opposite corners
rect->SetCorners( ppairs[0].p1, ppairs[2].p1 ); rect->SetCorners( ppairs[0].start, ppairs[2].start );
boundary->rectangle = rect; boundary->rectangle = rect;
} }
else else
{ {
#if 0 // PCBNEW user's edges are rarely this clean, let the router figure
// out the mess by using code at #else below.
PATH* path = new PATH( boundary ); PATH* path = new PATH( boundary );
path->layer_id = "pcb"; path->layer_id = "pcb";
...@@ -815,10 +900,21 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -815,10 +900,21 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
{ {
// unless its a closed polygon, this probably won't work, // unless its a closed polygon, this probably won't work,
// otherwise it will. // otherwise it will.
path->points.push_back( ppairs[i].p1 ); path->points.push_back( ppairs[i].start );
} }
boundary->paths.push_back( path ); boundary->paths.push_back( path );
#else
for( unsigned i=0; i<ppairs.size(); ++i )
{
PATH* path = new PATH( boundary );
boundary->paths.push_back( path );
path->layer_id = "pcb";
path->points.push_back( ppairs[i].start );
path->points.push_back( ppairs[i].end );
}
#endif
} }
pcb->structure->SetBOUNDARY( boundary ); pcb->structure->SetBOUNDARY( boundary );
...@@ -960,6 +1056,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -960,6 +1056,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
delete image; delete image;
} }
// @todo: this only works if the user has not modified the MODULE within the PCB
// and made it different from what is in the PCBNEW library. Need to test
// each image for uniqueness, not just based on name as is done here:
COMPONENT* comp = pcb->placement->LookupCOMPONENT( registered->image_id ); COMPONENT* comp = pcb->placement->LookupCOMPONENT( registered->image_id );
PLACE* place = new PLACE( comp ); PLACE* place = new PLACE( comp );
...@@ -968,8 +1068,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard ) ...@@ -968,8 +1068,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
place->SetRotation( module->m_Orient/10.0 ); place->SetRotation( module->m_Orient/10.0 );
place->SetVertex( mapPt( module->m_Pos ) ); place->SetVertex( mapPt( module->m_Pos ) );
place->component_id = CONV_TO_UTF8( module->GetReference() ); place->component_id = CONV_TO_UTF8( module->GetReference() );
// not supported by freerouting.net yet:
place->part_number = CONV_TO_UTF8( module->GetValue() ); place->part_number = CONV_TO_UTF8( module->GetValue() );
// module is flipped from bottom side, set side to T_back // module is flipped from bottom side, set side to T_back
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment