diff for gEDA PCB export in fped

I have

1) sorted out the tabbing

2) simplified > 1 element export by exporting elements in a layout (.pcb)

3) documented incompatibilities in the README

4) done it as a diff against origin master

let me know if you need anything else done

Cheers.

Erich

From dae69d9a63071a15c213c72e70b86fe963a67dd4 Mon Sep 17 00:00:00 2001
From: erich_heinzle <a1039181@gmail.com>
Date: Sun, 22 Jan 2017 23:48:57 +1030
Subject: [PATCH] support for export to gEDA format of single and multiple
 footprints in a .pcb layout
This commit is contained in:
Erich Heinzle 2017-01-23 00:09:07 +10:30 committed by Werner Almesberger
parent 688f2ab934
commit 7081258910
9 changed files with 387 additions and 1 deletions

View File

@ -3,6 +3,7 @@
#
# Written 2009-2012, 2015 by Werner Almesberger
# Copyright 2009-2012, 2015 by Werner Almesberger
# Copyright 2016, Erich Heinzle (gEDA additions)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -15,7 +16,7 @@ PREFIX ?= /usr/local
UPLOAD = www-data@downloads.qi-hardware.com:werner/fped/
OBJS = fped.o expr.o coord.o obj.o delete.o inst.o util.o error.o \
unparse.o file.o dump.o kicad.o postscript.o gnuplot.o meas.o \
unparse.o file.o dump.o kicad.o geda.o postscript.o gnuplot.o meas.o \
layer.o overlap.o hole.o tsort.o bitset.o \
cpp.o lex.yy.o y.tab.o \
gui.o gui_util.o gui_style.o gui_inst.o gui_status.o gui_canvas.o \

13
README
View File

@ -81,6 +81,19 @@ drawing reduces the risk of mistakes. Visualizing the construction
process and verificative measurements helps efficient and accurate
review.
Leveraging the work already done, and growing the intellectual commons
of available footprints has motivated the addition of an export to gEDA
pcb format option. Single or multiple footprints are exported in a
gEDA PCB layout (.pcb) file. A select all command can be used, followed
by a "disperse elements" command, to allow viewing of multiple elements
in the gEDA layout editor. An element can then be selected, cut to
buffer, and exported to a footprint (.fp) file with the usual menu
commands.
gEDA PCB format footprints are exported in centimil units. Pads with
offset centre holes are not faithfully reproduced; the pad is exported
with minimum dimensions and centred on the hole. Trapezoidal and
roundrect pads are not supported in gEDA.
Footprint definition file format
--------------------------------

View File

@ -3,6 +3,7 @@
*
* Written 2009, 2010, 2016 by Werner Almesberger
* Copyright 2009, 2010, 2016 by Werner Almesberger
* Copyright 2016, Erich Heinzle (gEDA additions)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -3,6 +3,7 @@
*
* Written 2009, 2010, 2016 by Werner Almesberger
* Copyright 2009, 2010, 2016 by Werner Almesberger
* Copyright 2016, Erich Heinzle (gEDA additions)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,6 +23,7 @@
#define MM_UNITS (1000.0*MICRON_UNITS)
#define UM_UNITS MICRON_UNITS
#define KICAD_UNIT (MIL_UNITS/10.0)
#define GEDA_UNIT (MIL_UNITS/100.0)
#define MIL_IN_MM 0.0254
#define UM_IN_MM 0.001
@ -79,6 +81,10 @@ static inline int units_to_kicad(unit_type u)
return (double) u/KICAD_UNIT;
}
static inline int units_to_geda(unit_type u)
{
return (double) u/GEDA_UNIT;
}
static inline int coord_eq(struct coord a, struct coord b)
{

16
file.c
View File

@ -3,6 +3,7 @@
*
* Written 2009-2012 by Werner Almesberger
* Copyright 2009-2012 by Werner Almesberger
* Copyright 2016, Erich Heinzle (gEDA additions)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -19,6 +20,7 @@
#include "dump.h"
#include "kicad.h"
#include "geda.h"
#include "postscript.h"
#include "gnuplot.h"
#include "util.h"
@ -171,6 +173,20 @@ void write_kicad(void)
}
}
void write_geda(void)
{
char *name;
if (save_file_name) {
name = set_extension(save_file_name, "pcb");
save_to(name, geda, NULL);
free(name);
} else {
if (!geda(stdout, NULL))
perror("stdout");
}
}
static void do_write_ps(int (*fn)(FILE *file, const char *one),
const char *one)

2
file.h
View File

@ -3,6 +3,7 @@
*
* Written 2009-2011 by Werner Almesberger
* Copyright 2009-2011 by Werner Almesberger
* Copyright 2016, Erich Heinzle (gEDA additions)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,6 +31,7 @@ int save_to(const char *name, int (*fn)(FILE *file, const char *one),
void save_fpd(void);
void write_kicad(void);
void write_geda(void);
void write_ps(const char *one);
void write_ps_fullpage(const char *one);
void write_gnuplot(const char *one);

322
geda.c Normal file
View File

@ -0,0 +1,322 @@
/*
* geda.c - Dump objects in the gEDA PCB board/module format
*
* Written 2009, 2011 by Werner Almesberger, and 2016 by Erich Heinzle
* Copyright 2009, 2011 by Werner Almesberger
* Copyright 2016, Erich Heinzle
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "coord.h"
#include "inst.h"
#include "geda.h"
static void geda_centric(struct coord a, struct coord b,
struct coord *center, struct coord *size)
{
struct coord min, max;
min.x = units_to_geda(a.x);
min.y = units_to_geda(a.y);
max.x = units_to_geda(b.x);
max.y = units_to_geda(b.y);
sort_coord(&min, &max);
size->x = max.x-min.x;
size->y = max.y-min.y;
center->x = (min.x+max.x)/2;
center->y = -(min.y+max.y)/2;
}
static unit_type geda_pad_width(struct coord size)
{
if (size.x >= size.y) {
return size.y;
} else {
return size.x;
}
}
static void geda_pad_start_finish(struct coord a, struct coord b,
struct coord *start, struct coord *finish)
{
struct coord size, center, min, max;
min.x = units_to_geda(a.x);
min.y = units_to_geda(a.y);
max.x = units_to_geda(b.x);
max.y = units_to_geda(b.y);
sort_coord(&min, &max);
size.x = max.x-min.x;
size.y = max.y-min.y;
center.x = (min.x+max.x)/2;
center.y = -(min.y+max.y)/2;
/* gEDA pads are drawn as a line, of a certain thickness */
if (size.x >= size.y) { /* wider than tall, width = size.y */
start->x = min.x + size.y/2;
start->y = -center.y;
finish->x = max.x - size.y/2;
finish->y = -center.y;
} else { /* taller than wide, width = size.x */
start->y = (min.y + size.x/2);
start->x = center.x;
finish->y = (max.y - size.x/2);
finish->x = center.x;
}
}
static void do_geda_drill(FILE *file, const struct inst *pad, struct coord *padSize)
{
const struct inst *hole = pad->u.pad.hole;
struct coord center, size;
if (!hole)
return;
geda_centric(hole->base, hole->u.hole.other, &center, &size);
fprintf(file, "%d %d ", center.x, -center.y); /* x,y position of hole */
if (padSize->x <= padSize->y) { /* sort out diameter of copper annulus, remembering obrounds*/
fprintf(file, "%d ", padSize->x);
} else {
fprintf(file, "%d ", padSize->y);
}
fprintf(file, "100 100 %d", size.x); /* default copper clearance, mask, then drill size */
}
static void geda_pad(FILE *file, const struct inst *inst)
{
struct coord center, size, start, finish;
geda_centric(inst->base, inst->u.pad.other, &center, &size);
if (inst->u.pad.hole) { /* pin */
/* Pin[X Y Thickness Clearance Mask Drill Name Number SFlags] */
fprintf(file, "\tPin[");
do_geda_drill(file, inst, &size); /* need pad size to figure out annulus */
fprintf(file, " \"%s\" \"%s\"", inst->u.pad.name, inst->u.pad.name);
if (inst->obj->u.pad.rounded) { /* round pin */
fprintf(file, " \"\"]\n");
} else { /* square pad, ignore octagonal for now */
fprintf(file, " \"square\"]\n");
}
} else { /* SMD */
/* Pad[X1 Y1 X2 Y2 Thickness Clearance Mask Name Number SFlags] */
geda_pad_start_finish(inst->base, inst->u.pad.other, &start, &finish);
fprintf(file, "\tPad[%d %d %d %d %d 100 100 \"%s\" \"%s\" \"square\"]\n", start.x, -start.y, finish.x, -finish.y, geda_pad_width(size), inst->u.pad.name, inst->u.pad.name);
}
}
static void geda_hole(FILE *file, const struct inst *inst)
{
struct coord center, size;
if (inst->u.hole.pad)
return;
geda_centric(inst->base, inst->u.hole.other, &center, &size);
/* Pin[X Y Thickness Clearance Mask Drill Name Number SFlags] */
fprintf(file, "\tPin[%d %d", center.x, center.y);
if (size.x <= size.y) { /* see which obround dimension is smallest */
fprintf(file, " %d 100 100 %d", size.x, size.x);
/* obround hole turned into round hole of diameter size.x */
} else {
fprintf(file, " %d 100 100 %d", size.y, size.y);
/* obround hole turned into round hole of diameter size.y */
}
fprintf(file, " \"\" \"\" \"hole\"]\n");
}
static void geda_line(FILE *file, const struct inst *inst)
{
/*
* Xstart, Ystart, Xend, Yend, Width
*/
fprintf(file, "\tElementLine[%d %d %d %d %d]\n",
units_to_geda(inst->base.x),
-units_to_geda(inst->base.y),
units_to_geda(inst->u.rect.end.x),
-units_to_geda(inst->u.rect.end.y),
units_to_geda(inst->u.rect.width));
}
static void geda_rect(FILE *file, const struct inst *inst)
{
unit_type xa, ya, xb, yb;
unit_type width;
xa = units_to_geda(inst->base.x);
ya = units_to_geda(inst->base.y);
xb = units_to_geda(inst->u.rect.end.x);
yb = units_to_geda(inst->u.rect.end.y);
width = units_to_geda(inst->u.rect.width);
fprintf(file, "\tElementLine[%d %d %d %d %d]\n",
xa, -ya, xa, -yb, width);
fprintf(file, "\tElementLine[%d %d %d %d %d]\n",
xa, -yb, xb, -yb, width);
fprintf(file, "\tElementLine[%d %d %d %d %d]\n",
xb, -yb, xb, -ya, width);
fprintf(file, "\tElementLine[%d %d %d %d %d]\n",
xb, -ya, xa, -ya, width);
}
static void geda_circ(FILE *file, const struct inst *inst)
{
/*
* Xcenter, Ycenter, Width, Height, startAngle, stopAngle, Width
*/
fprintf(file, "\tElementArc[ %d %d %d %d 0 360 %d]\n",
units_to_geda(inst->base.x),
-units_to_geda(inst->base.y),
units_to_geda(inst->u.arc.r),
units_to_geda(inst->u.arc.r),
units_to_geda(inst->u.arc.width));
}
static void geda_arc(FILE *file, const struct inst *inst)
{
double b;
/*
* Xcenter, Ycenter, Width, Height, startAngle, stopAngle, Width
*
*/
b = inst->u.arc.a1 - 180;
while (b <= 0)
b += 360;
while (b > 360)
b -= 360;
fprintf(file, "\tElementArc[%d %d %d %d %d %d %d]\n",
units_to_geda(inst->base.x),
-units_to_geda(inst->base.y),
units_to_geda(inst->u.arc.r),
units_to_geda(inst->u.arc.r),
(int) b,
(int) (inst->u.arc.a2-inst->u.arc.a1),
units_to_geda(inst->u.arc.width));
}
static void geda_layout_header(FILE *file)
{
fprintf(file, "# release: pcb 20110918\n\n");
fprintf(file, "# To read pcb files, the pcb version (or the git source date) must be >= the file version\n");
fprintf(file, "FileVersion[20070407]\n\n");
fprintf(file, "PCB[\"\" 600000 500000]\n\n");
fprintf(file, "Grid[2500.0 0 0 1]\n");
fprintf(file, "Cursor[2500 62500 0.000000]\n");
fprintf(file, "PolyArea[3100.006200]\n");
fprintf(file, "Thermal[0.500000]\n");
fprintf(file, "DRC[1200 900 1000 700 1500 1000]\n");
fprintf(file, "Flags(\"nameonpcb,clearnew,snappin\")\n");
fprintf(file, "Groups(\"1,3,4,c:2,5,6,s:7:8\")\n");
fprintf(file, "Styles[\"Signal,1000,7874,3150,2000:Power,2000,8661,3937,2000:Fat,8000,13780,4724,2500:Sig-tight,1000,6400,3150,1200\"]\n\n");
fprintf(file, "Attribute(\"PCB::grid::unit\" \"mil\")");
}
static void geda_layout_footer(FILE *file)
{
fprintf(file, "Layer(1 \"component\")\n(\n)\n");
fprintf(file, "Layer(2 \"solder\")\n(\n)\n");
fprintf(file, "Layer(3 \"comp-GND\")\n(\n)\n");
fprintf(file, "Layer(4 \"comp-power\")\n(\n)\n");
fprintf(file, "Layer(5 \"sold-GND\")\n(\n)\n");
fprintf(file, "Layer(6 \"sold-power\")\n(\n)\n");
fprintf(file, "Layer(7 \"signal3\")\n(\n)\n");
fprintf(file, "Layer(8 \"outline\")\n(\n)\n");
fprintf(file, "Layer(9 \"silk\")\n(\n)\n");
fprintf(file, "Layer(10 \"silk\")\n(\n)\n");
}
static void geda_inst(FILE *file, enum inst_prio prio, const struct inst *inst)
{
switch (prio) {
case ip_pad_copper:
case ip_pad_special:
geda_pad(file, inst);
break;
case ip_hole:
geda_hole(file, inst); /* obround is exported as a round circle */
break;
case ip_line:
geda_line(file, inst);
break;
case ip_rect:
geda_rect(file, inst);
break;
case ip_circ:
geda_circ(file, inst);
break;
case ip_arc:
geda_arc(file, inst);
break;
default:
/*
* Don't try to export vectors, frame references, or
* measurements.
*/
break;
}
}
static void geda_module(FILE *file, const struct pkg *pkg, time_t now)
{
enum inst_prio prio;
const struct inst *inst;
fprintf(file, "# Footprint generated by FPED utility\n");
fprintf(file, "Element[\"\" \"%s\" \"\" \"\" 0 0 -25590 -14874 0 100 \"\"]\n", pkg->name);
fprintf(file, "(\n");
FOR_INST_PRIOS_UP(prio) {
for (inst = pkgs->insts[prio]; inst; inst = inst->next)
geda_inst(file, prio, inst);
for (inst = pkg->insts[prio]; inst; inst = inst->next)
geda_inst(file, prio, inst);
}
fprintf(file, ")\n\n"); /* extra newline between elements */
}
int geda(FILE *file, const char *one)
{
const struct pkg *pkg;
time_t now = time(NULL);
assert(!one);
geda_layout_header(file); /* we place one or more elements in a layout file */
for (pkg = pkgs; pkg; pkg = pkg->next)
if (pkg->name)
fprintf(file, "# %s\n", pkg->name);
for (pkg = pkgs; pkg; pkg = pkg->next)
if (pkg->name)
geda_module(file, pkg, now);
geda_layout_footer(file);
fflush(file);
return !ferror(file);
}

23
geda.h Normal file
View File

@ -0,0 +1,23 @@
/*
* geda_pcb.h - Dump objects in the gEDA PCB board/module format
*
* Written 2009, 2011 by Werner Almesberger, 2016 by Erich Heinzle
* Copyright 2009, 2011 by Werner Almesberger
* Copyright 2016, Erich Heinzle
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef GEDA_H
#define GEDA_H
#include <stdio.h>
int geda(FILE *file, const char *one);
#endif /* !GEDA_H */

2
gui.c
View File

@ -3,6 +3,7 @@
*
* Written 2009-2012, 2015-2016 by Werner Almesberger
* Copyright 2009-2012, 2015-2016 by Werner Almesberger
* Copyright 2016, Erich Heinzle (gEDA additions)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -149,6 +150,7 @@ static GtkItemFactoryEntry menu_entries[] = {
{ "/File/Save as", NULL, save_as_fpd, 0, "<Item>" },
{ "/File/sep1", NULL, NULL, 0, "<Separator>" },
{ "/File/Write KiCad", NULL, write_kicad, 0, "<Item>" },
{ "/File/Write gEDA", NULL, write_geda, 0, "<Item>" },
{ "/File/Write Postscript",
NULL, write_ps, 0, "<Item>" },
{ "/File/sep2", NULL, NULL, 0, "<Separator>" },