fped/geda.c

322 lines
8.8 KiB
C

/*
* 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);
}