kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #07230
Realigned gencad patch
Fixed the via name issue too!
--
Lorenzo Marcantonio
Logos Srl
diff -w -u -r -x CMakeFiles -x '*cmake*' -x Makefile -x bitmaps_xpm -x .bzr ./pcbnew/class_pad.cpp ../kicad-bzr/pcbnew/class_pad.cpp
--- ./pcbnew/class_pad.cpp 2011-11-30 19:09:13.343385000 +0100
+++ ../kicad-bzr/pcbnew/class_pad.cpp 2011-11-29 19:54:30.409807034 +0100
@@ -854,31 +854,41 @@
{
int diff;
- if( (diff = padref->m_PadShape - padcmp->m_PadShape) )
+ if( diff = padref->m_PadShape - padcmp->m_PadShape)
return diff;
- if( (diff = padref->m_Size.x - padcmp->m_Size.x) )
+ if( diff = padref->m_DrillShape - padcmp->m_DrillShape)
return diff;
- if( (diff = padref->m_Size.y - padcmp->m_Size.y) )
+ if( diff = padref->m_Drill.x - padcmp->m_Drill.x )
return diff;
- if( (diff = padref->m_Offset.x - padcmp->m_Offset.x) )
+ if( diff = padref->m_Drill.y - padcmp->m_Drill.y )
return diff;
- if( (diff = padref->m_Offset.y - padcmp->m_Offset.y) )
+ if( diff = padref->m_Size.x - padcmp->m_Size.x )
return diff;
- if( (diff = padref->m_DeltaSize.x - padcmp->m_DeltaSize.x) )
+ if( diff = padref->m_Size.y - padcmp->m_Size.y )
return diff;
- if( (diff = padref->m_DeltaSize.y - padcmp->m_DeltaSize.y) )
+ if( diff = padref->m_Offset.x - padcmp->m_Offset.x )
+ return diff;
+
+ if( diff = padref->m_Offset.y - padcmp->m_Offset.y )
+ return diff;
+
+ if( diff = padref->m_DeltaSize.x - padcmp->m_DeltaSize.x )
+ return diff;
+
+ if( diff = padref->m_DeltaSize.y - padcmp->m_DeltaSize.y )
return diff;
// @todo check if export_gencad still works:
- // specctra_export needs this, but maybe export_gencad does not. added on
- // Jan 24 2008 by Dick.
- if( ( diff = padref->m_layerMask - padcmp->m_layerMask ) )
+ // specctra_export needs this, but maybe export_gencad does not.
+ // Lorenzo: XXX no idea about specctra, but gencad need it to
+ // implement padstacks!
+ if( diff = padref->m_layerMask - padcmp->m_layerMask )
return diff;
return 0;
diff -w -u -r -x CMakeFiles -x '*cmake*' -x Makefile -x bitmaps_xpm -x .bzr ./pcbnew/export_gencad.cpp ../kicad-bzr/pcbnew/export_gencad.cpp
--- ./pcbnew/export_gencad.cpp 2011-11-29 15:55:24.849044000 +0100
+++ ../kicad-bzr/pcbnew/export_gencad.cpp 2011-12-02 09:03:38.453354741 +0100
@@ -46,55 +46,75 @@
#include "class_edge_mod.h"
-bool CreateHeaderInfoData( FILE* file, PCB_EDIT_FRAME* frame );
-static void CreateTracksInfoData( FILE* file, BOARD* pcb );
-static void CreateBoardSection( FILE* file, BOARD* pcb );
-static void CreateComponentsSection( FILE* file, BOARD* pcb );
-static void CreateDevicesSection( FILE* file, BOARD* pcb );
-static void CreateRoutesSection( FILE* file, BOARD* pcb );
-static void CreateSignalsSection( FILE* file, BOARD* pcb );
-static void CreateShapesSection( FILE* file, BOARD* pcb );
-static void CreatePadsShapesSection( FILE* file, BOARD* pcb );
-static void CreatePadsStacksSection( FILE* file, BOARD* pcb );
+static bool CreateHeaderInfoData( FILE* aFile, PCB_EDIT_FRAME* frame );
+static void CreateArtworksSection( FILE* aFile);
+static void CreateTracksInfoData( FILE* aFile, BOARD* aPcb );
+static void CreateBoardSection( FILE* aFile, BOARD* aPcb );
+static void CreateComponentsSection( FILE* aFile, BOARD* aPcb );
+static void CreateDevicesSection( FILE* aFile, BOARD* aPcb );
+static void CreateRoutesSection( FILE* aFile, BOARD* aPcb );
+static void CreateSignalsSection( FILE* aFile, BOARD* aPcb );
+static void CreateShapesSection( FILE* aFile, BOARD* aPcb );
+static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb );
static void FootprintWriteShape( FILE* File, MODULE* module );
// layer name for Gencad export
-static const wxString GenCAD_Layer_Name[32] =
+static const wxString GenCADLayerName[32] =
{
wxT( "BOTTOM" ), wxT( "INNER1" ), wxT( "INNER2" ),
wxT( "INNER3" ), wxT( "INNER4" ), wxT( "INNER5" ),
wxT( "INNER6" ), wxT( "INNER7" ), wxT( "INNER8" ),
wxT( "INNER9" ), wxT( "INNER10" ), wxT( "INNER11" ),
wxT( "INNER12" ), wxT( "INNER13" ), wxT( "INNER14" ),
- wxT( "TOP" ), wxT( "adhecu" ), wxT( "adhecmp" ),
+ wxT( "TOP" ), wxT( "LAYER17" ), wxT( "LAYER18" ),
wxT( "SOLDERPASTE_BOTTOM" ), wxT( "SOLDERPASTE_TOP" ),
wxT( "SILKSCREEN_BOTTOM" ), wxT( "SILKSCREEN_TOP" ),
- wxT( "SOLDERMASK_BOTTOM" ), wxT( "SOLDERMASK_TOP" ), wxT( "drawings" ),
- wxT( "comments" ), wxT( "eco1" ), wxT( "eco2" ),
- wxT( "edges" ), wxT( "--" ), wxT( "--" ),
- wxT( "--" )
+ wxT( "SOLDERMASK_BOTTOM" ), wxT( "SOLDERMASK_TOP" ), wxT( "LAYER25" ),
+ wxT( "LAYER26" ), wxT( "LAYER27" ), wxT( "LAYER28" ),
+ wxT( "LAYER29" ), wxT( "LAYER30" ), wxT( "LAYER31" ),
+ wxT( "LAYER32" )
};
-int offsetX, offsetY;
-D_PAD* PadList;
+// flipped layer name for Gencad export (to make CAM350 imports correct)
+static const wxString GenCADLayerNameFlipped[32] =
+{
+ wxT( "TOP" ), wxT( "INNER14" ), wxT( "INNER13" ),
+ wxT( "INNER12" ), wxT( "INNER11" ), wxT( "INNER10" ),
+ wxT( "INNER9" ), wxT( "INNER8" ), wxT( "INNER7" ),
+ wxT( "INNER6" ), wxT( "INNER5" ), wxT( "INNER4" ),
+ wxT( "INNER3" ), wxT( "INNER2" ), wxT( "INNER1" ),
+ wxT( "BOTTOM" ), wxT( "LAYER17" ), wxT( "LAYER18" ),
+ wxT( "SOLDERPASTE_TOP" ), wxT( "SOLDERPASTE_BOTTOM" ),
+ wxT( "SILKSCREEN_TOP" ), wxT( "SILKSCREEN_BOTTOM" ),
+ wxT( "SOLDERMASK_TOP" ), wxT( "SOLDERMASK_BOTTOM" ), wxT( "LAYER25" ),
+ wxT( "LAYER26" ), wxT( "LAYER27" ), wxT( "LAYER28" ),
+ wxT( "LAYER29" ), wxT( "LAYER30" ), wxT( "LAYER31" ),
+ wxT( "LAYER32" )
+};
+
+// These are the export origin (the auxiliary axis)
+static int GencadOffsetX, GencadOffsetY;
+
+/* GerbTool chokes on units different than INCH so this is the conversion
+ factor */
+const static double SCALE_FACTOR = 10000.0;
-/* 2 helper functions to calculate coordinates of modules in gencad values (
- * GenCAD Y axis from bottom to top)
+/* Two helper functions to calculate coordinates of modules in gencad values
+ * (GenCAD Y axis from bottom to top)
*/
-static int mapXto( int x )
+static double MapXTo( int aX )
{
- return x - offsetX;
+ return (aX - GencadOffsetX) / SCALE_FACTOR;
}
-
-static int mapYto( int y )
+static double MapYTo( int aY )
{
- return offsetY - y;
+ return (GencadOffsetY - aY) / SCALE_FACTOR;
}
-
-void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& event )
+/* Driver function: processing starts here */
+void PCB_EDIT_FRAME::ExportToGenCAD( wxCommandEvent& aEvent )
{
wxFileName fn = GetScreen()->GetFileName();
wxString msg, ext, wildcard;
@@ -117,11 +137,16 @@
DisplayError( this, msg ); return;
}
- /* Update some board data, to ensure a reliable gencad export: */
+ SetLocaleTo_C_standard(); // No pesky decimal separators in gencad
+
+ // Update some board data, to ensure a reliable gencad export
GetBoard()->ComputeBoundingBox();
- offsetX = m_Auxiliary_Axis_Position.x;
- offsetY = m_Auxiliary_Axis_Position.y;
+ // Save the auxiliary origin for the rest of the module
+ GencadOffsetX = m_Auxiliary_Axis_Position.x;
+ GencadOffsetY = m_Auxiliary_Axis_Position.y;
+
+ // No idea on *why* this should be needed... maybe to fix net names?
Compile_Ratsnest( NULL, true );
/* Temporary modification of footprints that are flipped (i.e. on bottom
@@ -130,9 +155,10 @@
* that are given as normal orientation (non flipped, rotation = 0))
* these changes will be undone later
*/
+ BOARD* pcb = GetBoard();
MODULE* module;
- for( module = GetBoard()->m_Modules; module != NULL; module = module->Next() )
+ for( module = pcb->m_Modules; module != NULL; module = module->Next() )
{
module->flag = 0;
@@ -143,38 +169,33 @@
}
}
- // Create file header:
- CreateHeaderInfoData( file, this );
- CreateBoardSection( file, GetBoard() );
-
- /* Create TRACKS list
- * This is the section $TRACK) (track width sizes) */
- CreateTracksInfoData( file, GetBoard() );
-
- /* Create the shapes list
- * (shapes of pads and footprints */
- CreatePadsShapesSection( file, GetBoard() ); /* Must be called
- * before
- * CreatePadsStacksSection
- * and
- * CreateShapesSection()
- */
- CreatePadsStacksSection( file, GetBoard() );
- CreateShapesSection( file, GetBoard() );
-
- CreateDevicesSection( file, GetBoard() );
- CreateComponentsSection( file, GetBoard() );
-
- /* Create the list of Nets: */
- CreateSignalsSection( file, GetBoard() );
-
- // Creates the Routes section (i.e. the list of board tracks)
- CreateRoutesSection( file, GetBoard() );
+ /* Gencad has some mandatory and some optional sections: some importer
+ need the padstack section (which is optional) anyway. Also the
+ order of the section *is* important */
+
+ CreateHeaderInfoData( file, this ); // Gencad header
+ CreateBoardSection( file, pcb ); // Board perimeter
+
+ CreatePadsShapesSection( file, pcb ); // Pads and padstacks
+ CreateArtworksSection( file ); // Empty but mandatory
+
+ /* Gencad splits a component info in shape, component and device.
+ We don't do any sharing (it would be difficult since each module is
+ customizable after placement) */
+ CreateShapesSection( file, pcb );
+ CreateComponentsSection( file, pcb );
+ CreateDevicesSection( file, pcb );
+
+ // In a similar way the netlist is split in net, track and route
+ CreateSignalsSection( file, pcb );
+ CreateTracksInfoData( file, pcb );
+ CreateRoutesSection( file, pcb );
fclose( file );
+ SetLocaleTo_Default(); // revert to the current locale
- /* Undo the footprints modifications (flipped footprints) */
- for( module = GetBoard()->m_Modules; module != NULL; module = module->Next() )
+ // Undo the footprints modifications (flipped footprints)
+ for( module = pcb->m_Modules; module != NULL; module = module->Next() )
{
if( module->flag )
{
@@ -184,58 +205,96 @@
}
}
-
-static int Pad_list_Sort_by_Shapes( const void* refptr, const void* objptr )
+// Comparator for sorting pads with qsort
+static int PadListSortByShape( const void* aRefptr, const void* aObjptr )
{
- const D_PAD* padref = *(D_PAD**) refptr;
- const D_PAD* padcmp = *(D_PAD**) objptr;
+ const D_PAD* padref = *(D_PAD**) aRefptr;
+ const D_PAD* padcmp = *(D_PAD**) aObjptr;
return D_PAD::Compare( padref, padcmp );
}
+// Sort vias for uniqueness
+static int ViaSort(const void* aRefptr, const void* aObjptr )
+{
+ TRACK* padref = *(TRACK**)aRefptr;
+ TRACK* padcmp = *(TRACK**)aObjptr;
+
+ if( padref->m_Width != padcmp->m_Width )
+ return padref->m_Width-padcmp->m_Width;
+
+ if( padref->GetDrillValue() != padcmp->GetDrillValue() )
+ return padref->GetDrillValue()-padcmp->GetDrillValue();
+
+ if( padref->ReturnMaskLayer() != padcmp->ReturnMaskLayer() )
+ return padref->ReturnMaskLayer()-padcmp->ReturnMaskLayer();
+
+ return 0;
+}
+
+// The ARTWORKS section is empty but (officially) mandatory
+static void CreateArtworksSection( FILE* aFile )
+{
+ /* The artworks section is empty */
+ fputs( "$ARTWORKS\n", aFile );
+ fputs( "$ENDARTWORKS\n\n", aFile );
+}
-/* Creates the pads shapes list ( 1 shape per pad )
- * Uses .GetSubRatsnest member of class D_PAD, to handle the shape id (value 1
- * ..n) for pads shapes PAD1 to PADn
- *
- * The PADS section is used to describe the shape of all the pads used on the
- * printed circuit board. The PADS section must be included, even if only a
- * default pad is described and used for all pads.
- * The keywords used in the PADS section are:
- * $PADS
- * PAD <pad_name> <pad_type> <drill_size>
- * LINE <line_ref>
- * ARC <arc_ref>
- * CIRCLE <circle_ref>
- * RECTANGLE <rectangle_ref>
- * ATTRIBUTE <attrib_ref>
- * $ENDPADS
- * $PADS and $ENDPADS mark the PADS section of the GenCAD file. Each pad
- * description must start with a PAD keyword.
- * The layer in which a pad lies is defined in the SHAPE section of the GenCAD
- * specification.
- * The pad is always placed on a shape at the pad origin, or in a pad stack at
- * the pad stack origin.
- */
-void CreatePadsShapesSection( FILE* file, BOARD* pcb )
+// Emit PADS and PADSTACKS. They are sorted and emitted uniquely.
+// Via name is synthesized from their attributes, pads are numbered
+static void CreatePadsShapesSection( FILE* aFile, BOARD* aPcb )
{
std::vector<D_PAD*> pads;
+ std::vector<D_PAD*> padstacks;
+ std::vector<TRACK*> vias;
+ std::vector<TRACK*> viastacks;
+ padstacks.resize(1); // We count pads from 1
- const char* pad_type;
+ // The master layermask (i.e. the enabled layers) for padstack generation
+ unsigned master_layermask = aPcb->GetBoardDesignSettings()->GetEnabledLayers();
- fputs( "$PADS\n", file );
+ fputs( "$PADS\n", aFile );
- if( pcb->GetPadsCount() > 0 )
+ // Enumerate and sort the pads
+ if( aPcb->GetPadsCount() > 0 )
{
pads.insert( pads.end(),
- pcb->m_NetInfo->m_PadsFullList.begin(),
- pcb->m_NetInfo->m_PadsFullList.end() );
- qsort( &pads[0], pcb->GetPadsCount(), sizeof( D_PAD* ), Pad_list_Sort_by_Shapes );
+ aPcb->m_NetInfo->m_PadsFullList.begin(),
+ aPcb->m_NetInfo->m_PadsFullList.end() );
+ qsort( &pads[0], aPcb->GetPadsCount(), sizeof( D_PAD* ),
+ PadListSortByShape );
}
- D_PAD* old_pad = NULL;
- int pad_name_number = 0;
+ // The same for vias
+ for( TRACK* track = aPcb->m_Track; track != NULL; track = track->Next() )
+ {
+ if( track->Type() == PCB_VIA_T )
+ {
+ vias.push_back( track );
+ }
+ }
+ qsort( &vias[0], vias.size(), sizeof(TRACK*), ViaSort );
+
+ // Emit vias pads
+ TRACK* old_via = 0;
+ for( unsigned i = 0; i < vias.size(); i++ )
+ {
+ TRACK* via = vias[i];
+ if (old_via && 0 == ViaSort(&old_via, &via))
+ continue;
+ old_via = via;
+ viastacks.push_back(via);
+ fprintf( aFile, "PAD V%d.%d.%X ROUND %g\nCIRCLE 0 0 %g\n",
+ via->m_Width,via->GetDrillValue(),
+ via->ReturnMaskLayer(),
+ via->GetDrillValue()/SCALE_FACTOR,
+ via->m_Width/(SCALE_FACTOR*2) );
+ }
+
+ // Emit component pads
+ D_PAD* old_pad = 0;
+ int pad_name_number = 0;
for( unsigned i = 0; i<pads.size(); ++i )
{
D_PAD* pad = pads[i];
@@ -250,8 +309,9 @@
pad_name_number++;
pad->SetSubRatsnest( pad_name_number );
- fprintf( file, "PAD PAD%d", pad->GetSubRatsnest() );
+ fprintf( aFile, "PAD P%d", pad->GetSubRatsnest() );
+ padstacks.push_back(pad); // Will have its own padstack later
int dx = pad->m_Size.x / 2;
int dy = pad->m_Size.y / 2;
@@ -259,115 +319,169 @@
{
default:
case PAD_CIRCLE:
- pad_type = "ROUND";
- fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
- fprintf( file, "CIRCLE %d %d %d\n",
- pad->m_Offset.x, -pad->m_Offset.y, dx );
+ fprintf( aFile, " ROUND %g\n",
+ pad->m_Drill.x / SCALE_FACTOR );
+ /* Circle is center, radius */
+ fprintf( aFile, "CIRCLE %g %g %g\n",
+ pad->m_Offset.x / SCALE_FACTOR,
+ -pad->m_Offset.y / SCALE_FACTOR,
+ pad->m_Size.x / (SCALE_FACTOR*2) );
break;
case PAD_RECT:
- pad_type = "RECTANGULAR";
- fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
- fprintf( file, "RECTANGLE %d %d %d %d\n",
- pad->m_Offset.x - dx, -pad->m_Offset.y - dy,
- pad->m_Size.x, pad->m_Size.y );
+ fprintf( aFile, " RECTANGULAR %g\n",
+ pad->m_Drill.x / SCALE_FACTOR );
+ // Rectangle is begin, size *not* begin, end!
+ fprintf( aFile, "RECTANGLE %g %g %g %g\n",
+ (-dx + pad->m_Offset.x ) / SCALE_FACTOR,
+ (-dy - pad->m_Offset.y ) / SCALE_FACTOR,
+ dx / (SCALE_FACTOR/2) , dy / (SCALE_FACTOR/2) );
break;
- case PAD_OVAL: /* Create outline by 2 lines and 2 arcs */
+ case PAD_OVAL: // Create outline by 2 lines and 2 arcs
{
- pad_type = "FINGER";
- fprintf( file, " %s %d\n", pad_type, pad->m_Drill.x );
+ // OrCAD Layout call them OVAL or OBLONG - GenCAD call them FINGERs
+ fprintf( aFile, " FINGER %g\n",
+ pad->m_Drill.x / SCALE_FACTOR );
int dr = dx - dy;
+
if( dr >= 0 ) // Horizontal oval
{
int radius = dy;
- fprintf( file, "LINE %d %d %d %d\n",
- -dr + pad->m_Offset.x, -pad->m_Offset.y - radius,
- dr + pad->m_Offset.x, -pad->m_Offset.y - radius );
- fprintf( file, "ARC %d %d %d %d %d %d\n",
- dr + pad->m_Offset.x, -pad->m_Offset.y - radius,
- dr + pad->m_Offset.x, -pad->m_Offset.y + radius,
- dr + pad->m_Offset.x, -pad->m_Offset.y );
-
- fprintf( file, "LINE %d %d %d %d\n",
- dr + pad->m_Offset.x, -pad->m_Offset.y + radius,
- -dr + pad->m_Offset.x, -pad->m_Offset.y + radius );
- fprintf( file, "ARC %d %d %d %d %d %d\n",
- -dr + pad->m_Offset.x, -pad->m_Offset.y + radius,
- -dr + pad->m_Offset.x, -pad->m_Offset.y - radius,
- -dr + pad->m_Offset.x, -pad->m_Offset.y );
+ fprintf( aFile, "LINE %g %g %g %g\n",
+ (-dr + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y - radius) / SCALE_FACTOR,
+ (dr + pad->m_Offset.x ) / SCALE_FACTOR,
+ (-pad->m_Offset.y - radius) / SCALE_FACTOR );
+ // GenCAD arcs are (start, end, center)
+ fprintf( aFile, "ARC %g %g %g %g %g %g\n",
+ (dr + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y - radius) / SCALE_FACTOR,
+ (dr + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y + radius) / SCALE_FACTOR,
+ (dr + pad->m_Offset.x) / SCALE_FACTOR,
+ -pad->m_Offset.y / SCALE_FACTOR );
+
+ fprintf( aFile, "LINE %g %g %g %g\n",
+ (dr + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y + radius) / SCALE_FACTOR,
+ (-dr + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y + radius) / SCALE_FACTOR );
+ fprintf( aFile, "ARC %g %g %g %g %g %g\n",
+ (-dr + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y + radius) / SCALE_FACTOR,
+ (-dr + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y - radius) / SCALE_FACTOR,
+ (-dr + pad->m_Offset.x) / SCALE_FACTOR,
+ -pad->m_Offset.y / SCALE_FACTOR );
}
else // Vertical oval
{
dr = -dr;
int radius = dx;
- fprintf( file, "LINE %d %d %d %d\n",
- -radius + pad->m_Offset.x, -pad->m_Offset.y - dr,
- -radius + pad->m_Offset.x, -pad->m_Offset.y + dr );
- fprintf( file, "ARC %d %d %d %d %d %d\n",
- -radius + pad->m_Offset.x, -pad->m_Offset.y + dr,
- radius + pad->m_Offset.x, -pad->m_Offset.y + dr,
- pad->m_Offset.x, -pad->m_Offset.y + dr );
-
- fprintf( file, "LINE %d %d %d %d\n",
- radius + pad->m_Offset.x, -pad->m_Offset.y + dr,
- radius + pad->m_Offset.x, -pad->m_Offset.y - dr );
- fprintf( file, "ARC %d %d %d %d %d %d\n",
- radius + pad->m_Offset.x, -pad->m_Offset.y - dr,
- -radius + pad->m_Offset.x, -pad->m_Offset.y - dr,
- pad->m_Offset.x, -pad->m_Offset.y - dr );
+ fprintf( aFile, "LINE %g %g %g %g\n",
+ (-radius + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y - dr) / SCALE_FACTOR,
+ (-radius + pad->m_Offset.x ) / SCALE_FACTOR,
+ (-pad->m_Offset.y + dr) / SCALE_FACTOR );
+ fprintf( aFile, "ARC %g %g %g %g %g %g\n",
+ (-radius + pad->m_Offset.x ) / SCALE_FACTOR,
+ (-pad->m_Offset.y + dr) / SCALE_FACTOR,
+ (radius + pad->m_Offset.x ) / SCALE_FACTOR,
+ (-pad->m_Offset.y + dr) / SCALE_FACTOR,
+ pad->m_Offset.x / SCALE_FACTOR,
+ (-pad->m_Offset.y + dr) / SCALE_FACTOR );
+
+ fprintf( aFile, "LINE %g %g %g %g\n",
+ (radius + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y + dr) / SCALE_FACTOR,
+ (radius + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y - dr) / SCALE_FACTOR );
+ fprintf( aFile, "ARC %g %g %g %g %g %g\n",
+ (radius + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y - dr) / SCALE_FACTOR,
+ (-radius + pad->m_Offset.x) / SCALE_FACTOR,
+ (-pad->m_Offset.y - dr) / SCALE_FACTOR,
+ pad->m_Offset.x / SCALE_FACTOR,
+ (-pad->m_Offset.y - dr) / SCALE_FACTOR );
}
break;
}
case PAD_TRAPEZOID:
- pad_type = "POLYGON";
+ fprintf( aFile, " POLYGON %g\n",
+ pad->m_Drill.x / SCALE_FACTOR );
+ // XXX TO BE IMPLEMENTED! and I don't know if it could be actually imported by something
break;
}
}
+ fputs( "\n$ENDPADS\n\n", aFile );
- fputs( "$ENDPADS\n\n", file );
+ // Now emit the padstacks definitions, using the combined layer masks
+ fputs( "$PADSTACKS\n", aFile );
+
+ // Via padstacks
+ for( unsigned i = 0; i < viastacks.size(); i++ )
+ {
+ TRACK *via = viastacks[i];
+ unsigned mask = via->ReturnMaskLayer() & master_layermask;
+ fprintf( aFile, "PADSTACK VIA%d.%d.%X %g\n",
+ via->m_Width, via->GetDrillValue(), mask,
+ via->GetDrillValue() / SCALE_FACTOR );
+
+ for( int layer = 0; layer < 32; layer++)
+ {
+ if( mask & (1<<layer) )
+ {
+ fprintf( aFile, "PAD V%d.%d.%X %s 0 0\n",
+ via->m_Width, via->GetDrillValue(),
+ mask,
+ TO_UTF8( GenCADLayerName[layer]) );
+ }
}
+ }
+ /* Component padstacks
+ CAM350 don't apply correctly the FLIP semantics for padstacks, i.e. doesn't
+ swap the top and bottom layers... so I need to define the shape as MIRRORX
+ and define a separate 'flipped' padstack... until it appears yet another
+ noncompliant importer */
+ for( unsigned i = 1; i < padstacks.size(); i++ )
+ {
+ D_PAD *pad = padstacks[i];
+ // Straight padstack
+ fprintf( aFile, "PADSTACK PAD%d %g\n", i,
+ pad->m_Drill.x / SCALE_FACTOR);
+ for( int layer = 0; layer < 32; layer++ )
+ {
+ if( pad->m_layerMask & (1<<layer) & master_layermask )
+ {
+ fprintf( aFile, "PAD P%d %s 0 0\n", i,
+ TO_UTF8( GenCADLayerName[layer] ) );
+ }
+ }
-/*The PADSTACKS section is optional, and is used to describe how a group of
- * pads are
- * arranged. The keywords used in the PADSTACKS section are:
- * $PADSTACKS
- * PADSTACK <pad_name> <drill_size>
- * PAD <pad_name> <layer> <rot> <mirror>
- * ATTRIBUTE <attrib_ref>
- * $ENDPADSTACKS
- * $PADSTACKS and $ENDPADSTACKS mark the PADSTACKS section of the GenCAD file.
- */
-void CreatePadsStacksSection( FILE* file, BOARD* pcb )
+ // Flipped padstack
+ fprintf( aFile, "PADSTACK PAD%dF %g\n", i,
+ pad->m_Drill.x / SCALE_FACTOR);
+ for( int layer = 0; layer < 32; layer++ )
+ {
+ if( pad->m_layerMask & (1<<layer) & master_layermask )
{
- fputs( "$PADSTACKS\n", file );
- fputs( "$ENDPADSTACKS\n\n", file );
+ fprintf( aFile, "PAD P%d %s 0 0\n", i,
+ TO_UTF8( GenCADLayerNameFlipped[layer] ) );
+ }
+ }
+ }
+ fputs( "$ENDPADSTACKS\n\n", aFile );
}
/* Creates the footprint shape list.
- * We must use one shape for identical footprint (i.e. come from the same
- * footprint in lib)
- * But because pads shapes and positions can be easily modified on board,
- * a shape is created by footprint found.
- * (todo : compare footprints shapes and creates only one shape for all
- * footprints found having the same shape)
- * The shape is always given in orientation 0, position 0 not flipped
- *
- * Syntax:
- * $SHAPES
- * SHAPE <shape_name>
- * INSERT <string> here <string> = "TH"
- * shape_descr (line, arc ..)
- * PIN <pin_name> <pad_name> <x_y_ref> <layer> <rot> <mirror>
- *
- * SHAPE <shape_name>
- * ..
- * $ENDSHAPES
+ * Since module shape is customizable after the placement we cannot share them;
+ * instead we opt for the one-module-one-shape-one-component-one-device approach
*/
-void CreateShapesSection( FILE* file, BOARD* pcb )
+static void CreateShapesSection( FILE* aFile, BOARD* aPcb )
{
MODULE* module;
D_PAD* pad;
@@ -376,80 +490,73 @@
wxString pinname;
const char* mirror = "0";
- fputs( "$SHAPES\n", file );
+ fputs( "$SHAPES\n", aFile );
- for( module = pcb->m_Modules; module != NULL; module = module->Next() )
+ for( module = aPcb->m_Modules; module != NULL; module = module->Next() )
{
- FootprintWriteShape( file, module );
+ FootprintWriteShape( aFile, module );
for( pad = module->m_Pads; pad != NULL; pad = pad->Next() )
{
+ /* Funny thing: GenCAD requires the pad side even if you use
+ padstacks (which are theorically optional but gerbtools
+ *requires* them). Now the trouble thing is that 'BOTTOM'
+ is interpreted by someone as a padstack flip even
+ if the spec explicitly says it's not... */
layer = "ALL";
if( ( pad->m_layerMask & ALL_CU_LAYERS ) == LAYER_BACK )
{
- if( module->GetLayer() == LAYER_N_FRONT )
- layer = "BOTTOM";
- else
- layer = "TOP";
+ layer = ( module->flag ) ? "TOP" : "BOTTOM";
}
else if( ( pad->m_layerMask & ALL_CU_LAYERS ) == LAYER_FRONT )
{
- if( module->GetLayer() == LAYER_N_FRONT )
- layer = "TOP";
- else
- layer = "BOTTOM";
+ layer = ( module->flag ) ? "BOTTOM" : "TOP";
}
pad->ReturnStringPadName( pinname );
if( pinname.IsEmpty() )
- pinname = wxT( "noname" );
+ pinname = wxT( "none" );
orient = pad->m_Orient - module->m_Orient;
NORMALIZE_ANGLE_POS( orient );
- fprintf( file, "PIN %s PAD%d %d %d %s %d %s",
- TO_UTF8( pinname ), pad->GetSubRatsnest(),
- pad->m_Pos0.x, -pad->m_Pos0.y,
- layer, orient / 10, mirror );
-
- if( orient % 10 )
- fprintf( file, " .%d", orient % 10 );
- fprintf( file, "\n" );
+ // Bottom side modules use the flipped padstack
+ fprintf( aFile, (module->flag) ?
+ "PIN %s PAD%dF %g %g %s %g %s\n" :
+ "PIN %s PAD%d %g %g %s %g %s\n",
+ TO_UTF8( pinname ), pad->GetSubRatsnest(),
+ pad->m_Pos0.x / SCALE_FACTOR,
+ -pad->m_Pos0.y / SCALE_FACTOR,
+ layer, orient / 10.0, mirror );
}
}
- fputs( "$ENDSHAPES\n\n", file );
+ fputs( "$ENDSHAPES\n\n", aFile );
}
-
/* Creates the section $COMPONENTS (Footprints placement)
- * When a footprint is on bottom side of the board::
- * shapes are given with option "FLIP" and "MIRRORX".
- * - But shapes remain given like component not mirrored and not flipped
- * - orientation is given like if where not mirrored and not flipped.
+ * Bottom side components are difficult to handle: shapes must be mirrored or
+ * flipped, silk layers need to be handled correctly and so on. Also it seems
+ * that *noone* follows the specs...
*/
-void CreateComponentsSection( FILE* file, BOARD* pcb )
+static void CreateComponentsSection( FILE* aFile, BOARD* aPcb )
{
- MODULE* module = pcb->m_Modules;
- TEXTE_MODULE* PtTexte;
- const char* mirror;
- const char* flip;
- int ii;
- fputs( "$COMPONENTS\n", file );
+ fputs( "$COMPONENTS\n", aFile );
- for( ; module != NULL; module = module->Next() )
+ for(MODULE* module = aPcb->m_Modules ; module != NULL; module = module->Next() )
{
+ TEXTE_MODULE* textmod;
+ const char* mirror;
+ const char* flip;
int orient = module->m_Orient;
if( module->flag )
{
- mirror = "MIRRORX"; // Mirrored relative to X axis
- flip = "FLIP"; // Normal shape description ( gencad
- // viewer must show it flipped and
- // mirrored)
+ mirror = "0";
+ flip = "FLIP";
NEGATE_AND_NORMALIZE_ANGLE_POS( orient );
}
else
@@ -458,61 +565,61 @@
flip = "0";
}
- fprintf( file, "COMPONENT %s\n", TO_UTF8( module->m_Reference->m_Text ) );
- fprintf( file, "DEVICE %s\n", TO_UTF8( module->m_Reference->m_Text ) );
- fprintf( file, "PLACE %d %d\n", mapXto( module->m_Pos.x ), mapYto( module->m_Pos.y ) );
- fprintf( file, "LAYER %s\n", (module->flag) ? "BOTTOM" : "TOP" );
- fprintf( file, "ROTATION %d", orient / 10 );
-
- if( orient % 10 )
- fprintf( file, ".%d", orient % 10 );
-
- fputs( "\n", file );
-
- fprintf( file, "SHAPE %s %s %s\n", TO_UTF8( module->m_Reference->m_Text ), mirror, flip );
-
- /* creates texts (ref and value) */
- PtTexte = module->m_Reference;
-
- for( ii = 0; ii < 2; ii++ )
- {
- int orient = PtTexte->m_Orient;
- wxString layer = GenCAD_Layer_Name[SILKSCREEN_N_FRONT];
- fprintf( file, "TEXT %d %d %d %d.%d %s %s \"%s\"",
- PtTexte->m_Pos0.x, -PtTexte->m_Pos0.y,
- PtTexte->m_Size.x,
- orient / 10, orient % 10,
+ fprintf( aFile, "\nCOMPONENT %s\n",
+ TO_UTF8( module->m_Reference->m_Text ) );
+ fprintf( aFile, "DEVICE %s_%s\n",
+ TO_UTF8( module->m_Reference->m_Text ),
+ TO_UTF8( module->m_Value->m_Text ) );
+ fprintf( aFile, "PLACE %g %g\n",
+ MapXTo( module->m_Pos.x ),
+ MapYTo( module->m_Pos.y ) );
+ fprintf( aFile, "LAYER %s\n",
+ (module->flag) ? "BOTTOM" : "TOP" );
+ fprintf( aFile, "ROTATION %g\n",
+ orient / 10.0 );
+ fprintf( aFile, "SHAPE %s %s %s\n",
+ TO_UTF8( module->m_Reference->m_Text ),
+ mirror, flip );
+
+ // Text on silk layer: RefDes and value (are they actually useful?)
+ textmod = module->m_Reference;
+
+ for( int ii = 0; ii < 2; ii++ )
+ {
+ int orient = textmod->m_Orient;
+ wxString layer = GenCADLayerName[(module->flag) ?
+ SILKSCREEN_N_BACK : SILKSCREEN_N_FRONT];
+
+ fprintf( aFile, "TEXT %g %g %g %g %s %s \"%s\"",
+ textmod->m_Pos0.x / SCALE_FACTOR,
+ -textmod->m_Pos0.y / SCALE_FACTOR,
+ textmod->m_Size.x / SCALE_FACTOR,
+ orient / 10.0,
mirror,
TO_UTF8( layer ),
- TO_UTF8( PtTexte->m_Text )
- );
+ TO_UTF8( textmod->m_Text ) );
- fprintf( file, " 0 0 %d %d\n",
- (int) ( PtTexte->m_Size.x * PtTexte->m_Text.Len() ),
- (int) PtTexte->m_Size.y );
+ // Please note, the width is approx
+ fprintf( aFile, " 0 0 %g %g\n",
+ (textmod->m_Size.x * textmod->m_Text.Len())
+ / SCALE_FACTOR,
+ textmod->m_Size.y / SCALE_FACTOR );
- PtTexte = module->m_Value;
+ textmod = module->m_Value; // Dirty trick for the second iteration
}
- //put a comment:
- fprintf( file, "SHEET Part %s %s\n",
+ // The SHEET is a 'generic description' for referencing the component
+ fprintf( aFile, "SHEET \"RefDes: %s, Value: %s\"\n",
TO_UTF8( module->m_Reference->m_Text ),
TO_UTF8( module->m_Value->m_Text ) );
}
- fputs( "$ENDCOMPONENTS\n\n", file );
+ fputs( "$ENDCOMPONENTS\n\n", aFile );
}
-
-/* Creates the list of Nets:
- * $SIGNALS
- * SIGNAL <net name>
- * NODE <component name> <pin name>
- * ...
- * NODE <component name> <pin name>
- * $ENDSIGNALS
- */
-void CreateSignalsSection( FILE* file, BOARD* pcb )
+/* Emit the netlist (which is actually the thing for which GenCAD is used these
+ * days!); tracks are handled later */
+static void CreateSignalsSection( FILE* aFile, BOARD* aPcb )
{
wxString msg;
NETINFO_ITEM* net;
@@ -520,11 +627,11 @@
MODULE* module;
int NbNoConn = 1;
- fputs( "$SIGNALS\n", file );
+ fputs( "$SIGNALS\n", aFile );
- for( unsigned ii = 0; ii < pcb->m_NetInfo->GetCount(); ii++ )
+ for( unsigned ii = 0; ii < aPcb->m_NetInfo->GetCount(); ii++ )
{
- net = pcb->m_NetInfo->GetNetItem( ii );
+ net = aPcb->m_NetInfo->GetNetItem( ii );
if( net->GetNetname() == wxEmptyString ) // dummy netlist (no connection)
{
@@ -537,10 +644,10 @@
msg = wxT( "SIGNAL " ) + net->GetNetname();
- fputs( TO_UTF8( msg ), file );
- fputs( "\n", file );
+ fputs( TO_UTF8( msg ), aFile );
+ fputs( "\n", aFile );
- for( module = pcb->m_Modules; module != NULL; module = module->Next() )
+ for( module = aPcb->m_Modules; module != NULL; module = module->Next() )
{
for( pad = module->m_Pads; pad != NULL; pad = pad->Next() )
{
@@ -550,53 +657,56 @@
continue;
pad->ReturnStringPadName( padname );
- msg.Printf( wxT( "NODE %s %.4s" ),
+ msg.Printf( wxT( "NODE %s %s" ),
GetChars( module->m_Reference->m_Text ),
GetChars( padname ) );
- fputs( TO_UTF8( msg ), file );
- fputs( "\n", file );
+ fputs( TO_UTF8( msg ), aFile );
+ fputs( "\n", aFile );
}
}
}
- fputs( "$ENDSIGNALS\n\n", file );
+ fputs( "$ENDSIGNALS\n\n", aFile );
}
-/* Creates the section $HEADER ... $ENDHEADER
- */
-bool CreateHeaderInfoData( FILE* file, PCB_EDIT_FRAME* frame )
+/* Creates the header section; some of the data come from the frame
+ * (actually the screen), not from the pcb */
+static bool CreateHeaderInfoData( FILE* aFile, PCB_EDIT_FRAME* aFrame )
{
wxString msg;
- PCB_SCREEN* screen = (PCB_SCREEN*) ( frame->GetScreen() );
+ PCB_SCREEN* screen = (PCB_SCREEN*) ( aFrame->GetScreen() );
- fputs( "$HEADER\n", file );
- fputs( "GENCAD 1.4\n", file );
- msg = wxT( "USER " ) + wxGetApp().GetAppName() + wxT( " " ) + GetBuildVersion();
- fputs( TO_UTF8( msg ), file ); fputs( "\n", file );
- msg = wxT( "DRAWING " ) + screen->GetFileName();
- fputs( TO_UTF8( msg ), file ); fputs( "\n", file );
- msg = wxT( "REVISION " ) + screen->m_Revision + wxT( " " ) + screen->m_Date;
- fputs( TO_UTF8( msg ), file ); fputs( "\n", file );
- msg.Printf( wxT( "UNITS USER %d" ), PCB_INTERNAL_UNIT );
- fputs( TO_UTF8( msg ), file ); fputs( "\n", file );
- msg.Printf( wxT( "ORIGIN %d %d" ),
- mapXto( frame->m_Auxiliary_Axis_Position.x ),
- mapYto( frame->m_Auxiliary_Axis_Position.y ) );
- fputs( TO_UTF8( msg ), file ); fputs( "\n", file );
- fputs( "INTERTRACK 0\n", file );
- fputs( "$ENDHEADER\n\n", file );
+ fputs( "$HEADER\n", aFile );
+ fputs( "GENCAD 1.4\n", aFile );
+
+ // Please note: GenCAD syntax requires quoted strings if they can contain spaces
+ msg.Printf( wxT( "USER \"%s %s\"\n" ),
+ GetChars( wxGetApp().GetAppName() ),
+ GetChars( GetBuildVersion() ) );
+ fputs( TO_UTF8( msg ), aFile );
+ msg = wxT( "DRAWING \"" ) + screen->GetFileName() + wxT( "\"\n" );
+ fputs( TO_UTF8( msg ), aFile );
+ msg = wxT( "REVISION \"" ) + screen->m_Revision + wxT( " " ) +
+ screen->m_Date + wxT( "\"\n" );
+ fputs( TO_UTF8( msg ), aFile );
+ fputs( "UNITS INCH\n", aFile);
+ msg.Printf( wxT( "ORIGIN %g %g\n" ),
+ MapXTo( aFrame->m_Auxiliary_Axis_Position.x ),
+ MapYTo( aFrame->m_Auxiliary_Axis_Position.y ) );
+ fputs( TO_UTF8( msg ), aFile );
+ fputs( "INTERTRACK 0\n", aFile );
+ fputs( "$ENDHEADER\n\n", aFile );
return true;
}
-
/*
* Sort function used to sort tracks segments:
* items are sorted by netcode, then by width then by layer
*/
-static int Track_list_Sort_by_Netcode( const void* refptr, const void* objptr )
+static int TrackListSortByNetcode( const void* refptr, const void* objptr )
{
const TRACK* ref, * cmp;
int diff;
@@ -626,20 +736,21 @@
* $ENROUTE
* Track segments must be sorted by nets
*/
-void CreateRoutesSection( FILE* file, BOARD* pcb )
+static void CreateRoutesSection( FILE* aFile, BOARD* aPcb )
{
TRACK* track, ** tracklist;
int vianum = 1;
int old_netcode, old_width, old_layer;
int nbitems, ii;
+ unsigned master_layermask = aPcb->GetBoardDesignSettings()->GetEnabledLayers();
// Count items
nbitems = 0;
- for( track = pcb->m_Track; track != NULL; track = track->Next() )
+ for( track = aPcb->m_Track; track != NULL; track = track->Next() )
nbitems++;
- for( track = pcb->m_Zone; track != NULL; track = track->Next() )
+ for( track = aPcb->m_Zone; track != NULL; track = track->Next() )
{
if( track->Type() == PCB_ZONE_T )
nbitems++;
@@ -649,10 +760,10 @@
nbitems = 0;
- for( track = pcb->m_Track; track != NULL; track = track->Next() )
+ for( track = aPcb->m_Track; track != NULL; track = track->Next() )
tracklist[nbitems++] = track;
- for( track = pcb->m_Zone; track != NULL; track = track->Next() )
+ for( track = aPcb->m_Zone; track != NULL; track = track->Next() )
{
if( track->Type() == PCB_ZONE_T )
tracklist[nbitems++] = track;
@@ -660,9 +771,9 @@
tracklist[nbitems] = NULL;
- qsort( tracklist, nbitems, sizeof(TRACK*), Track_list_Sort_by_Netcode );
+ qsort( tracklist, nbitems, sizeof(TRACK*), TrackListSortByNetcode );
- fputs( "$ROUTES\n", file );
+ fputs( "$ROUTES\n", aFile );
old_netcode = -1; old_width = -1; old_layer = -1;
@@ -673,7 +784,7 @@
if( old_netcode != track->GetNet() )
{
old_netcode = track->GetNet();
- NETINFO_ITEM* net = pcb->FindNet( track->GetNet() );
+ NETINFO_ITEM* net = aPcb->FindNet( track->GetNet() );
wxString netname;
if( net && (net->GetNetname() != wxEmptyString) )
@@ -681,13 +792,13 @@
else
netname = wxT( "_noname_" );
- fprintf( file, "ROUTE %s\n", TO_UTF8( netname ) );
+ fprintf( aFile, "ROUTE %s\n", TO_UTF8( netname ) );
}
if( old_width != track->m_Width )
{
old_width = track->m_Width;
- fprintf( file, "TRACK TRACK%d\n", track->m_Width );
+ fprintf( aFile, "TRACK TRACK%d\n", track->m_Width );
}
if( (track->Type() == PCB_TRACE_T) || (track->Type() == PCB_ZONE_T) )
@@ -695,24 +806,25 @@
if( old_layer != track->GetLayer() )
{
old_layer = track->GetLayer();
- fprintf( file, "LAYER %s\n",
- TO_UTF8( GenCAD_Layer_Name[track->GetLayer() & 0x1F] ) );
+ fprintf( aFile, "LAYER %s\n",
+ TO_UTF8( GenCADLayerName[track->GetLayer() & 0x1F] ) );
}
- fprintf( file, "LINE %d %d %d %d\n",
- mapXto( track->m_Start.x ), mapYto( track->m_Start.y ),
- mapXto( track->m_End.x ), mapYto( track->m_End.y ) );
+ fprintf( aFile, "LINE %g %g %g %g\n",
+ MapXTo( track->m_Start.x ), MapYTo( track->m_Start.y ),
+ MapXTo( track->m_End.x ), MapYTo( track->m_End.y ) );
}
if( track->Type() == PCB_VIA_T )
{
- fprintf( file, "VIA viapad%d %d %d ALL %d via%d\n",
- track->m_Width,
- mapXto( track->m_Start.x ), mapYto( track->m_Start.y ),
- track->GetDrillValue(), vianum++ );
+ fprintf( aFile, "VIA VIA%d.%d.%X %g %g ALL %g via%d\n",
+ track->m_Width,track->GetDrillValue(),
+ track->ReturnMaskLayer() & master_layermask,
+ MapXTo( track->m_Start.x ), MapYTo( track->m_Start.y ),
+ track->GetDrillValue()/SCALE_FACTOR, vianum++ );
}
}
- fputs( "$ENDROUTES\n\n", file );
+ fputs( "$ENDROUTES\n\n", aFile );
delete tracklist;
}
@@ -722,64 +834,54 @@
* This is a list of footprints properties
* ( Shapes are in section $SHAPE )
*/
-void CreateDevicesSection( FILE* file, BOARD* pcb )
+static void CreateDevicesSection( FILE* aFile, BOARD* aPcb )
{
MODULE* module;
- D_PAD* pad;
-
- fputs( "$DEVICES\n", file );
- for( module = pcb->m_Modules; module != NULL; module = module->Next() )
- {
- fprintf( file, "DEVICE %s\n", TO_UTF8( module->m_Reference->m_Text ) );
- fprintf( file, "PART %s\n", TO_UTF8( module->m_LibRef ) );
- fprintf( file, "TYPE %s\n", "UNKNOWN" );
+ fputs( "$DEVICES\n", aFile );
- for( pad = module->m_Pads; pad != NULL; pad = pad->Next() )
+ for( module = aPcb->m_Modules; module != NULL; module = module->Next() )
{
- fprintf( file, "PINDESCR %.4s", pad->m_Padname );
-
- if( pad->GetNetname() == wxEmptyString )
- fputs( " NoConn\n", file );
- else
- fprintf( file, " %.4s\n", pad->m_Padname );
- }
-
- fprintf( file, "ATTRIBUTE %s\n", TO_UTF8( module->m_Value->m_Text ) );
+ fprintf( aFile, "DEVICE \"%s\"\n", TO_UTF8( module->m_Reference->m_Text ) );
+ fprintf( aFile, "PART \"%s\"\n", TO_UTF8( module->m_Value->m_Text ) );
+ fprintf( aFile, "PACKAGE \"%s\"\n", TO_UTF8( module->m_LibRef ) );
+ // The TYPE attribute is almost freeform
+ const char *ty = "TH";
+ if( module->m_Attributs & MOD_CMS )
+ ty = "SMD";
+ if( module->m_Attributs & MOD_VIRTUAL )
+ ty = "VIRTUAL";
+ fprintf( aFile, "TYPE %s\n", ty );
}
- fputs( "$ENDDEVICES\n\n", file );
+ fputs( "$ENDDEVICES\n\n", aFile );
}
/* Creates the section $BOARD.
- * We output here only the board boundary box
+ * We output here only the board perimeter
*/
-void CreateBoardSection( FILE* file, BOARD* pcb )
+static void CreateBoardSection( FILE* aFile, BOARD* aPcb )
{
- fputs( "$BOARD\n", file );
- fprintf( file, "LINE %d %d %d %d\n",
- mapXto( pcb->m_BoundaryBox.m_Pos.x ),
- mapYto( pcb->m_BoundaryBox.m_Pos.y ),
- mapXto( pcb->m_BoundaryBox.GetRight() ),
- mapYto( pcb->m_BoundaryBox.m_Pos.y ) );
- fprintf( file, "LINE %d %d %d %d\n",
- mapXto( pcb->m_BoundaryBox.GetRight() ),
- mapYto( pcb->m_BoundaryBox.m_Pos.y ),
- mapXto( pcb->m_BoundaryBox.GetRight() ),
- mapYto( pcb->m_BoundaryBox.GetBottom() ) );
- fprintf( file, "LINE %d %d %d %d\n",
- mapXto( pcb->m_BoundaryBox.GetRight() ),
- mapYto( pcb->m_BoundaryBox.GetBottom() ),
- mapXto( pcb->m_BoundaryBox.m_Pos.x ),
- mapYto( pcb->m_BoundaryBox.GetBottom() ) );
- fprintf( file, "LINE %d %d %d %d\n",
- mapXto( pcb->m_BoundaryBox.m_Pos.x ),
- mapYto( pcb->m_BoundaryBox.GetBottom() ),
- mapXto( pcb->m_BoundaryBox.m_Pos.x ),
- mapYto( pcb->m_BoundaryBox.m_Pos.y ) );
-
- fputs( "$ENDBOARD\n\n", file );
+ fputs( "$BOARD\n", aFile );
+ // Extract the board edges
+ for (EDA_ITEM* drawing = aPcb->m_Drawings;
+ drawing != 0;
+ drawing = drawing->Next() )
+ {
+ if ( drawing->Type() == PCB_LINE_T )
+ {
+ DRAWSEGMENT *drawseg = dynamic_cast<DRAWSEGMENT*>(drawing);
+ if (drawseg->GetLayer() == EDGE_N)
+ {
+ // XXX GenCAD supports arc boundaries but I've seen nothing that reads them
+ fprintf( aFile, "LINE %g %g %g %g\n",
+ MapXTo(drawseg->m_Start.x), MapYTo(drawseg->m_Start.y),
+ MapXTo(drawseg->m_End.x), MapYTo(drawseg->m_End.y));
+ }
+ }
+ }
+ fputs( "$ENDBOARD\n\n", aFile );
}
@@ -793,18 +895,19 @@
* Each tool name is build like this: "TRACK" + track width.
* For instance for a width = 120 : name = "TRACK120".
*/
-void CreateTracksInfoData( FILE* file, BOARD* pcb )
+static void CreateTracksInfoData( FILE* aFile, BOARD* aPcb )
{
TRACK* track;
int last_width = -1;
- /* Find thickness used for traces. */
+ // Find thickness used for traces
+ // XXX could use the same sorting approach used for pads
std::vector <int> trackinfo;
unsigned ii;
- for( track = pcb->m_Track; track != NULL; track = track->Next() )
+ for( track = aPcb->m_Track; track != NULL; track = track->Next() )
{
if( last_width != track->m_Width ) // Find a thickness already used.
{
@@ -821,7 +924,7 @@
}
}
- for( track = pcb->m_Zone; track != NULL; track = track->Next() )
+ for( track = aPcb->m_Zone; track != NULL; track = track->Next() )
{
if( last_width != track->m_Width ) // Find a thickness already used.
{
@@ -839,116 +942,147 @@
}
// Write data
- fputs( "$TRACKS\n", file );
+ fputs( "$TRACKS\n", aFile );
for( ii = 0; ii < trackinfo.size(); ii++ )
{
- fprintf( file, "TRACK TRACK%d %d\n", trackinfo[ii], trackinfo[ii] );
+ fprintf( aFile, "TRACK TRACK%d %g\n", trackinfo[ii],
+ trackinfo[ii] / SCALE_FACTOR );
}
- fputs( "$ENDTRACKS\n\n", file );
+ fputs( "$ENDTRACKS\n\n", aFile );
}
/* Creates the shape of a footprint (section SHAPE)
* The shape is always given "normal" (Orient 0, not mirrored)
- * Syntax:
- * SHAPE <shape_name>
- * INSERT <string> here <string> = "TH"
- * shape_descr (line, arc ..):
- * LINE startX startY endX endY
- * ARC startX startY endX endY centreX centreY
- * PAD_CIRCLE centreX scentreY radius
+ * It's almost guaranteed that the silk layer will be imported wrong but
+ * the shape also contains the pads!
*/
-void FootprintWriteShape( FILE* file, MODULE* module )
+static void FootprintWriteShape( FILE* aFile, MODULE* module )
{
- EDGE_MODULE* edge;
- EDA_ITEM* item;
- int y_axis_sign = -1; // Control Y axis change sign (as normal
- // module / mirror axis and conventions)
+ EDGE_MODULE* PtEdge;
+ EDA_ITEM* PtStruct;
+ // Control Y axis change sign for flipped modules
+ int Yaxis_sign = -1;
+
+ // Flip for bottom side components
+ if( module->flag )
+ Yaxis_sign = 1;
/* creates header: */
- fprintf( file, "SHAPE %s\n", TO_UTF8( module->m_Reference->m_Text ) );
- fprintf( file, "INSERT %s\n", (module->m_Attributs & MOD_CMS) ? "SMD" : "TH" );
+ fprintf( aFile, "\nSHAPE %s\n", TO_UTF8( module->m_Reference->m_Text ) );
+
+ if( module->m_Attributs & MOD_VIRTUAL )
+ {
+ fprintf( aFile, "INSERT SMD\n");
+ }
+ else
+ {
+ if( module->m_Attributs & MOD_CMS )
+ {
+ fprintf( aFile, "INSERT SMD\n");
+ }
+ else
+ {
+ fprintf( aFile, "INSERT TH\n" );
+ }
+ }
+
+#if 0 /* ATTRIBUTE name and value is unspecified and the original exporter
+ * got the syntax wrong, so CAM350 rejected the whole shape! */
- /* creates Attributes */
if( module->m_Attributs != MOD_DEFAULT )
{
- fprintf( file, "ATTRIBUTE" );
+ fprintf( aFile, "ATTRIBUTE" );
if( module->m_Attributs & MOD_CMS )
- fprintf( file, " PAD_SMD" );
+ fprintf( aFile, " PAD_SMD" );
if( module->m_Attributs & MOD_VIRTUAL )
- fprintf( file, " VIRTUAL" );
+ fprintf( aFile, " VIRTUAL" );
- fprintf( file, "\n" );
+ fprintf( aFile, "\n" );
}
+#endif
- /* creates Drawing */
- item = module->m_Drawings;
-
- for( ; item != NULL; item = item->Next() )
+ // Silk outline; wildly interpreted by various importers:
+ // CAM350 read it right but only closed shapes
+ // ProntoPlace double-flip it (at least the pads are correct)
+ // GerberTool usually get it right...
+ for( PtStruct = module->m_Drawings; PtStruct != NULL; PtStruct = PtStruct->Next() )
{
- switch( item->Type() )
+ switch( PtStruct->Type() )
{
case PCB_MODULE_TEXT_T:
+ // If we wanted to export text, this is not the correct section
break;
case PCB_MODULE_EDGE_T:
- edge = (EDGE_MODULE*) item;
-
- switch( edge->m_Shape )
+ PtEdge = (EDGE_MODULE*) PtStruct;
+ if( PtEdge->GetLayer() == SILKSCREEN_N_FRONT
+ || PtEdge->GetLayer() == SILKSCREEN_N_BACK )
+ {
+ switch( PtEdge->m_Shape )
{
case S_SEGMENT:
- fprintf( file, "LINE %d %d %d %d\n",
- edge->m_Start0.x, y_axis_sign * edge->m_Start0.y,
- edge->m_End0.x, y_axis_sign * edge->m_End0.y );
+ fprintf( aFile, "LINE %g %g %g %g\n",
+ (PtEdge->m_Start0.x) / SCALE_FACTOR,
+ (Yaxis_sign * PtEdge->m_Start0.y) / SCALE_FACTOR,
+ (PtEdge->m_End0.x) / SCALE_FACTOR,
+ (Yaxis_sign * PtEdge->m_End0.y ) / SCALE_FACTOR);
break;
case S_CIRCLE:
{
- int radius = (int) hypot( (double) ( edge->m_End0.x - edge->m_Start0.x ),
- (double) ( edge->m_End0.y - edge->m_Start0.y ) );
- fprintf( file, "CIRCLE %d %d %d\n",
- edge->m_Start0.x, y_axis_sign * edge->m_Start0.y, radius );
+ int radius = (int) hypot(
+ (double) ( PtEdge->m_End0.x - PtEdge->m_Start0.x ),
+ (double) ( PtEdge->m_End0.y - PtEdge->m_Start0.y ) );
+ fprintf( aFile, "CIRCLE %g %g %g\n",
+ PtEdge->m_Start0.x / SCALE_FACTOR,
+ Yaxis_sign * PtEdge->m_Start0.y / SCALE_FACTOR,
+ radius / SCALE_FACTOR );
break;
}
- case S_ARC: /* print ARC x,y start x,y end x,y center */
- { // Arcs are defined counter clockwise (positive trigonometric)
- // from the start point to the end point (0 to 360 degrees)
- wxPoint arcStart, arcEnd;
-
- // edge->m_Start0 is the arc center relative to the shape position
- // edge->m_End0 is the arc start point relative to the shape position
- arcStart = edge->m_End0;
-
- // calculate arcEnd arc end point relative to the shape position, in Pcbnew
- // coordinates
- arcEnd = arcStart;
- RotatePoint( &arcEnd, edge->m_Start0, -edge->m_Angle );
-
- // due to difference between Pcbnew and gencad, swap arc start and arc end
- EXCHG(arcEnd, arcStart);
-
- // print arc shape:
- fprintf( file, "ARC %d %d %d %d %d %d\n",
- arcStart.x, y_axis_sign * arcStart.y, // Start point
- arcEnd.x, y_axis_sign * arcEnd.y, // End point
- edge->m_Start0.x, y_axis_sign * edge->m_Start0.y );
+ case S_ARC:
+ {
+ int arcendx, arcendy;
+ arcendx = PtEdge->m_End0.x - PtEdge->m_Start0.x;
+ arcendy = PtEdge->m_End0.y - PtEdge->m_Start0.y;
+ RotatePoint( &arcendx, &arcendy, -PtEdge->m_Angle );
+ arcendx += PtEdge->m_Start0.x;
+ arcendy += PtEdge->m_Start0.y;
+ if (Yaxis_sign == -1) {
+ // Flipping Y flips the arc direction too
+ fprintf( aFile, "ARC %g %g %g %g %g %g\n",
+ (arcendx) / SCALE_FACTOR,
+ (Yaxis_sign * arcendy) / SCALE_FACTOR,
+ (PtEdge->m_End0.x) / SCALE_FACTOR,
+ (Yaxis_sign * PtEdge->m_End0.y) / SCALE_FACTOR,
+ (PtEdge->m_Start0.x) / SCALE_FACTOR,
+ (Yaxis_sign * PtEdge->m_Start0.y) / SCALE_FACTOR );
+ } else {
+ fprintf( aFile, "ARC %g %g %g %g %g %g\n",
+ (PtEdge->m_End0.x) / SCALE_FACTOR,
+ (Yaxis_sign * PtEdge->m_End0.y) / SCALE_FACTOR,
+ (arcendx) / SCALE_FACTOR,
+ (Yaxis_sign * arcendy) / SCALE_FACTOR,
+ (PtEdge->m_Start0.x) / SCALE_FACTOR,
+ (Yaxis_sign * PtEdge->m_Start0.y) / SCALE_FACTOR );
+ }
break;
}
default:
DisplayError( NULL, wxT( "Type Edge Module invalid." ) );
break;
- } /* end switch PtEdge->m_Shape */
-
+ }
+ }
break;
default:
break;
- } /* End switch Items type */
+ }
}
}
Follow ups