Commit b9f9d539 authored by dickelbeck's avatar dickelbeck
Browse files

more amazing free specctra software

parent 4a0b5607
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -5,6 +5,21 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with
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>
================================================================================
+pcbnew:
+1 −1
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@
    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 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.
*/    

+6 −7
Original line number Diff line number Diff line
@@ -695,19 +695,19 @@ public:
        
        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", 
                               LEXER::GetTokenText( Type() ),
                               quote, layer_id.c_str(), quote, 
                               aperture_width );

        int wrapNest = MAX( nestLevel+1, 6 );
        for( unsigned i=0;  i<points.size();  ++i )
        {
            if( perLine > RIGHTMARGIN )
            {
                out->Print( 0, "\n" );
                perLine = out->Print( nestLevel+1, "%s", "" );
                newline = "\n";
                perLine = out->Print( wrapNest, "%s", "" );
            }
            else
                perLine += out->Print( 0, "  " );
@@ -717,10 +717,9 @@ public:

        if( aperture_type == T_square )
        {
            out->Print( 0, "\n" );
            out->Print( nestLevel+1, "(aperture_type square))\n" );
            out->Print( 0, "(aperture_type square)" );
        }
        else
        
        out->Print( 0, ")%s", newline ); 
    }
};
+160 −62
Original line number Diff line number Diff line
@@ -74,6 +74,9 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
    bool            ok = true;
    wxString        errorText;

    BASE_SCREEN*    screen = GetScreen();
    bool            wasModified = screen->IsModify() && !screen->IsSave();
    
    db.SetPCB( SPECCTRA_DB::MakePCB() );

    try 
@@ -92,6 +95,12 @@ void WinEDA_PcbFrame::ExportToSPECCTRA( wxCommandEvent& event )
        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 )
    {
        // @todo display a message saying the export is complete.
@@ -105,8 +114,8 @@ namespace DSN {

struct POINT_PAIR
{
    POINT       p1;         ///< start
    POINT       p2;         ///< end
    POINT       start;
    POINT       end;
    BOARD_ITEM* item;       ///< the item which has these points, TRACK or DRAWSEGMENT
};
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 )
{
    POINT temp = pair.p1;
    pair.p1 = pair.p2;
    pair.p2 = temp;
    POINT temp = pair.start;
    pair.start = pair.end;
    pair.end   = temp;
}


@@ -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
 * 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 )
 */
static void swapEnds( POINT_PAIRS& aList )
{
    POINT   temp;
    
    if( aList.size() <= 1 )
    if( !aList.size() )
        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 )
            swap( aList[i] ); 
        sorted.push_back( *source.begin() );
        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] );
            swap( aList[i+1] );
            ++i;    // skip next one, we swapped i+1 here
            int ndx = ABS(result)-1; 
            sorted.push_back( source[ ndx ] );
            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 )
        for( unsigned i=0;  i<aList.size();  ++i )
        {
            if( i < aList.size()-1 )
                if( aList[i].p2 != aList[i+1].p1 )
                if( aList[i].end != aList[i+1].start )
                    return false;
            
            if( aList[i].p1.x != aList[i].p2.x 
            &&  aList[i].p1.y != aList[i].p2.y )
            if( aList[i].start.x != aList[i].end.x 
            &&  aList[i].start.y != aList[i].end.y )
                return false;
        }
        
        return ( aList[0].p1 == aList[3].p2 );
        return ( aList[0].start == aList[3].end );
    }
    return false;
}
@@ -316,7 +373,11 @@ IMAGE* SPECCTRA_DB::makeIMAGE( MODULE* aModule )
            
            pin->padstack_id = padstack->padstack_id;
            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 )
        // padstacks.size()-1 is the index of the matching padstack in LIBRARY::padstacks
        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
        // 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 
@@ -462,7 +515,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
                        
                        circle->SetLayerId( layerName );
                        circle->SetDiameter( diameter );
                        circle->SetVertex( padOffset );
                        ++coppers;
                    }
                }
@@ -486,9 +538,6 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
                POINT   lowerLeft( -dx, -dy );
                POINT   upperRight( dx, dy );

                lowerLeft  += padOffset;
                upperRight += padOffset;

                for( int layer=0;  layer<reportedLayers;  ++layer )
                {
                    if( doLayer[layer] )
@@ -540,38 +589,55 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            path = makePath( 
                                    POINT( -dr + padOffset.x, padOffset.y - radius ),     // aStart
                                    POINT(  dr + padOffset.x, padOffset.y - radius ),     // aEnd
                                    POINT( -dr, -radius ),      // aStart
                                    POINT(  dr, -radius ),      // aEnd
                                    layerName );
                            shape->SetShape( path );
                            
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            // @todo: this 1/2 circle arc needs to be split into two quarter circle arcs 
                            qarc = makeArc( 
                                    POINT(  dr + padOffset.x, padOffset.y - radius),      // aStart
                                    POINT(  dr + padOffset.x, padOffset.y + radius),      // aEnd
                                    POINT(  dr + padOffset.x, padOffset.y ),              // aCenter
                                    POINT(  dr, -radius),       // aStart
                                    POINT(  dr, 0.0 ),          // aEnd
                                    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 );
                            shape->SetShape( qarc );
    
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            path = makePath( 
                                    POINT(  dr + padOffset.x, padOffset.y + radius ),     // aStart
                                    POINT( -dr + padOffset.x, padOffset.y + radius ),     // aEnd
                                    POINT(  dr,  radius ),      // aStart
                                    POINT( -dr,  radius ),      // aEnd
                                    layerName );
                            shape->SetShape( path );
    
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            // @todo: this 1/2 circle arc needs to be split into two quarter circle arcs 
                            qarc = makeArc( 
                                    POINT( -dr + padOffset.x, padOffset.y + radius),      // aStart
                                    POINT( -dr + padOffset.x, padOffset.y - radius),      // aEnd
                                    POINT( -dr + padOffset.x, padOffset.y ),              // aCenter
                                    POINT( -dr, radius),        // aStart
                                    POINT( -dr, 0.0),           // aEnd
                                    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 );
                            shape->SetShape( qarc );
                            
                            ++coppers;
                        }
                    }
@@ -595,38 +661,55 @@ void SPECCTRA_DB::makePADSTACKs( BOARD* aBoard, TYPE_COLLECTOR& aPads )
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            path = makePath( 
                                    POINT( -radius + padOffset.x, padOffset.y - dr ),   // aStart
                                    POINT( -radius + padOffset.x, padOffset.y + dr ),   // aEnd
                                    POINT( -radius, -dr ),      // aStart
                                    POINT( -radius,  dr ),      // aEnd
                                    layerName );
                            shape->SetShape( path );
    
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            // @todo: this 1/2 circle arc needs to be split into two quarter circle arcs 
                            qarc = makeArc( 
                                    POINT( -radius + padOffset.x, padOffset.y + dr ),   // aStart
                                    POINT(  radius + padOffset.x, padOffset.y + dr),    // aEnd
                                    POINT(  padOffset.x, padOffset.y +dr ),             // aCenter
                                    POINT( -radius, dr ),       // aStart
                                    POINT(  0.0,    dy ),       // aEnd
                                    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 );
                            shape->SetShape( qarc );
    
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            path = makePath( 
                                    POINT(  radius + padOffset.x, padOffset.y + dr ),   // aStart
                                    POINT(  radius + padOffset.x, padOffset.y - dr ),   // aEnd
                                    POINT(  radius,  dr ),      // aStart
                                    POINT(  radius, -dr ),      // aEnd
                                    layerName );
                            shape->SetShape( path );
    
                            shape = new SHAPE( padstack );
                            padstack->Append( shape );
                            // @todo: this 1/2 circle arc needs to be split into two quarter circle arcs 
                            qarc = makeArc( 
                                    POINT(  radius + padOffset.x, padOffset.y - dr),    // aStart
                                    POINT( -radius + padOffset.x, padOffset.y - dr),    // aEnd
                                    POINT( padOffset.x, padOffset.y - dr ),             // aCenter
                                    POINT( radius, -dr ),       // aStart
                                    POINT( 0.0,    -dy ),       // aEnd
                                    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 );
                            shape->SetShape( qarc );
                            
                            ++coppers;
                        }
                    }
@@ -774,8 +857,8 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
            
            if( item->GetLayer() == EDGE_N )
            {
                pair.p1 = mapPt( item->m_Start );
                pair.p2 = mapPt( item->m_End );
                pair.start = mapPt( item->m_Start );
                pair.end = mapPt( item->m_End );
                pair.item = item;
                ppairs.push_back( pair );
                haveEdges = true;
@@ -802,12 +885,14 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
                rect->layer_id = "pcb";
                
                // opposite corners
                rect->SetCorners( ppairs[0].p1, ppairs[2].p1 );
                rect->SetCorners( ppairs[0].start, ppairs[2].start );
                
                boundary->rectangle = rect;
            }
            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->layer_id = "pcb";
@@ -815,10 +900,21 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
                {
                    // unless its a closed polygon, this probably won't work,
                    // otherwise it will.
                    path->points.push_back( ppairs[i].p1 );
                    path->points.push_back( ppairs[i].start );
                }
                
                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 );
@@ -960,6 +1056,10 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
                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 );
            
            PLACE* place = new PLACE( comp );
@@ -968,8 +1068,6 @@ void SPECCTRA_DB::FromBOARD( BOARD* aBoard )
            place->SetRotation( module->m_Orient/10.0 );
            place->SetVertex( mapPt( module->m_Pos ) );
            place->component_id = CONV_TO_UTF8( module->GetReference() );
            
            // not supported by freerouting.net yet:
            place->part_number  = CONV_TO_UTF8( module->GetValue() );
            
            // module is flipped from bottom side, set side to T_back