1
0
mirror of git://projects.qi-hardware.com/eda-tools.git synced 2024-11-22 20:14:04 +02:00

rename sch2fig to eeshow

This commit is contained in:
Werner Almesberger 2016-08-02 11:00:08 -03:00
parent 590724e3bb
commit a941a5f246
42 changed files with 5910 additions and 0 deletions

25
eeshow/DEMO Normal file
View File

@ -0,0 +1,25 @@
# Prerequisites (depends on distribution)
apt-get install libcairo2-dev
apt-get install libgit2-dev
apt-get install qiv
# Get all the things we need
git clone http://neo900.org/git/ee.git newdir
cd newdir/hw
git clone git://projects.qi-hardware.com/kicad-libs.git
git clone git://projects.qi-hardware.com/eda-tools.git
make -C eda-tools/eeshow
# Generate PNG for old, new, and difference
LIBS="neo900.lib kicad-libs/components/powered.lib"
eda-tools/eeshow/eeshow $LIBS 6a9f71:neo900_SS_5.sch -- png -s 2 -o old.png
eda-tools/eeshow/eeshow $LIBS neo900_SS_5.sch -- png -s 2 -o new.png
eda-tools/eeshow/eeshow $LIBS 6a9f71:neo900_SS_5.sch -- \
diff -s 2 -o diff.png $LIBS neo900_SS_5.sch
# View the result
qiv -t diff.png old.png new.png

91
eeshow/Makefile Normal file
View File

@ -0,0 +1,91 @@
#
# Makefile - build eeshow
#
# Written 2016 by Werner Almesberger
# Copyright 2016 by Werner Almesberger
#
# 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.
#
NAME = eeshow
OBJS = main.o sch-parse.o sch-render.o lib-parse.o lib-render.o \
file.o git-file.o \
style.o fig.o record.o cro.o diff.o gfx.o dwg.o text.o misc.o
CFLAGS = -g -Wall -Wextra -Wno-unused-parameter -Wshadow \
-Wmissing-prototypes -Wmissing-declarations \
`pkg-config --cflags cairo` \
`pkg-config --cflags libgit2`
LDLIBS = -lm \
`pkg-config --libs cairo` \
`pkg-config --libs libgit2`
include ../common/Makefile.c-common
.PHONY: test neo900 sch test testref png pngref diff view newref
all:: $(NAME)
$(NAME): $(OBJS)
$(CC) -o $(NAME) $(OBJS) $(LDLIBS)
#----- Test sheet -------------------------------------------------------------
sch:
eeschema test.sch
test: $(NAME)
./$(NAME) test.lib test.sch >out.fig
fig2dev -L png -m 2 out.fig _out.png
[ ! -r ref.png ] || \
compare -metric AE ref.png _out.png _diff.png || \
qiv -t -R -D _diff.png ref.png _out.png
testref: $(NAME)
./$(NAME) test.lib test.sch | fig2dev -L png -m 2 >ref.png
png: $(NAME)
./$(NAME) test.lib test.sch -- png -o _out.png -s 2
[ ! -r pngref.png ] || \
compare -metric AE pngref.png _out.png _diff.png || \
qiv -t -R -D _diff.png pngref.png _out.png
pngref: $(NAME)
./$(NAME) test.lib test.sch -- png -o pngref.png -s 2
clean::
rm -f out.fig _out.png _diff.png
#----- Render Neo900 schematics -----------------------------------------------
NEO900_HW = ../../../n9/ee/hw
KICAD_LIBS = ../../kicad-libs/components
SHEET ?= 12
neo900: $(NAME)
./$(NAME) $(NEO900_HW)/neo900.lib \
$(KICAD_LIBS)/powered.lib \
$(NEO900_HW)/neo900_SS_$(SHEET).sch \
>out.fig
neo900.pdf: $(NAME) sch2pdf neo900-template.fig
./sch2pdf -o $@ -t neo900-template.fig \
$(NEO900_HW)/neo900.lib $(KICAD_LIBS)/powered.lib \
$(NEO900_HW)/neo900.sch
#----- Regression test based on Neo900 schematics -----------------------------
diff: $(NAME)
test/genpng test out
test/comp test || $(MAKE) view
view:
qiv -t -R -D `echo test/_diff*.png | \
sed 's/\([^ ]*\)_diff\([^ ]*\)/\1_diff\2 \1ref\2 \1out\2/g'`
newref:
test/genpng test ref

24
eeshow/TODO Normal file
View File

@ -0,0 +1,24 @@
- better text size guessing also for FIG
- unify alignment, direction
- support fonts attributes ?
- support line thickness ?
- ~ as overline (grep for ~ in out.fig)
- glabel: build for "right" style, then rotate poly (like hlabel)
- show open pins / wires
- check remaining alignment / direction / rotation cases in switch statements
- support mirroring (and detect-complain if unexpected) [should be done now]
- pin shapes (inverted, clock, etc.)
- optionally display pin type
- find libraries (e.g., from .pro)
- PDF TOC
- let user set PNG size or zoom level
- parse .kicad_wks
- on parse error, politely complain, don't terminate;
convert abort / assert(0) to proper error indications
- implement destructors
- check for memory leaks
- record.c (bb_rot): implement bounding boxes for text
- nesting gfx in diff is a huge kludge, caused by global vars in gfx.c
- move path name guessing into file.c
- return indication of whether diff found any differences
- in diff, pass only options understood by cairo_png

461
eeshow/cro.c Normal file
View File

@ -0,0 +1,461 @@
/*
* cro.c - Cairo graphics back-end
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h>
#include <cairo/cairo.h>
#include <cairo/cairo-pdf.h>
#include "util.h"
#include "style.h"
#include "text.h"
#include "gfx.h"
#include "record.h"
#include "main.h"
#include "cro.h"
/*
* FIG works with 1/1200 in
* KiCad works with mil
* 1 point = 1/72 in
*/
#define DEFAULT_SCALE (72.0 / 1200)
struct cro_ctx {
struct record record; /* must be first */
int xo, yo;
float scale;
cairo_t *cr;
cairo_surface_t *s;
struct record *sheets; /* for PDF */
unsigned n_sheets;
const char *output_name;
};
static inline int cd(struct cro_ctx *cc, int x)
{
return x * cc->scale;
}
static inline int cx(struct cro_ctx *cc, int x)
{
return cc->xo + x * cc->scale;
}
static inline int xc(struct cro_ctx *cc, int x)
{
return (x - cc->xo) / cc->scale;
}
static inline int cy(struct cro_ctx *cc, int y)
{
return cc->yo + y * cc->scale;
}
static inline float pt(struct cro_ctx *cc, int x)
{
return cd(cc, x) * 72 * 1.5 / 1200.0;
}
static void set_color(cairo_t *cr, int color)
{
uint32_t c;
if (color < 0)
return;
c = color_rgb[color];
cairo_set_source_rgb(cr, (c >> 16) / 255.0, ((c >> 8) & 255) / 255.0,
(c & 255) / 255.0);
}
static void paint(cairo_t *cr, int color, int fill_color)
{
if (fill_color != COLOR_NONE) {
set_color(cr, fill_color);
if (color == COLOR_NONE)
cairo_fill(cr);
else
cairo_fill_preserve(cr);
}
if (color != COLOR_NONE) {
set_color(cr, color);
cairo_stroke(cr);
}
}
/* ----- General items ----------------------------------------------------- */
static void cr_line(void *ctx, int sx, int sy, int ex, int ey,
int color, unsigned layer)
{
struct cro_ctx *cc = ctx;
static const double dashes[] = { 4, 2 };
cairo_new_path(cc->cr);
cairo_move_to(cc->cr, cx(cc, sx), cy(cc, sy));
cairo_line_to(cc->cr, cx(cc, ex), cy(cc, ey));
cairo_set_dash(cc->cr, dashes, ARRAY_ELEMENTS(dashes), 0);
paint(cc->cr, color, COLOR_NONE);
cairo_set_dash(cc->cr, NULL, 0, 0);
}
static void cr_poly(void *ctx,
int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer)
{
struct cro_ctx *cc = ctx;
bool closed;
int i;
if (points < 2)
return;
closed = x[0] == x[points - 1] && y[0] == y[points - 1];
cairo_new_path(cc->cr);
cairo_move_to(cc->cr, cx(cc, x[0]), cy(cc, y[0]));
for (i = 1; i != points - closed; i++)
cairo_line_to(cc->cr, cx(cc, x[i]), cy(cc, y[i]));
if (closed)
cairo_close_path(cc->cr);
paint(cc->cr, color, fill_color);
}
static void cr_circ(void *ctx, int x, int y, int r,
int color, int fill_color, unsigned layer)
{
struct cro_ctx *cc = ctx;
cairo_new_path(cc->cr);
cairo_arc(cc->cr, cx(cc, x), cy(cc, y), cd(cc, r), 0, 2 * M_PI);
paint(cc->cr, color, fill_color);
}
static void cr_arc(void *ctx, int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer)
{
struct cro_ctx *cc = ctx;
cairo_new_path(cc->cr);
cairo_arc(cc->cr, cx(cc, x), cy(cc, y), cd(cc, r),
-ea / 180.0 * M_PI, -sa / 180.0 * M_PI);
paint(cc->cr, color, fill_color);
}
#define TEXT_STRETCH 1.3
static void cr_text(void *ctx, int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer)
{
struct cro_ctx *cc = ctx;
cairo_text_extents_t ext;
cairo_matrix_t m;
cairo_set_font_size(cc->cr, cd(cc, size) * TEXT_STRETCH);
cairo_text_extents(cc->cr, s, &ext);
set_color(cc->cr, color);
cairo_move_to(cc->cr, cx(cc, x), cy(cc, y));
cairo_get_matrix(cc->cr, &m);
cairo_rotate(cc->cr, -rot / 180.0 * M_PI);
switch (align) {
case text_min:
break;
case text_mid:
cairo_rel_move_to(cc->cr, -ext.width / 2.0, 0);
break;
case text_max:
cairo_rel_move_to(cc->cr, -ext.width, 0);
break;
default:
abort();
}
cairo_show_text(cc->cr, s);
cairo_set_matrix(cc->cr, &m);
}
static unsigned cr_text_width(void *ctx, const char *s, unsigned size)
{
struct cro_ctx *cc = ctx;
cairo_text_extents_t ext;
cairo_set_font_size(cc->cr, cx(cc, size) * TEXT_STRETCH);
cairo_text_extents(cc->cr, s, &ext);
return xc(cc, ext.width) * 1.05; /* @@@ Cairo seems to underestimate */
}
/* ----- Initializatio and termination ------------------------------------- */
static const struct gfx_ops real_cro_ops = {
.name = "cairo",
.line = cr_line,
.poly = cr_poly,
.circ = cr_circ,
.arc = cr_arc,
.text = cr_text,
.text_width = cr_text_width,
};
static struct cro_ctx *init_common(int argc, char *const *argv)
{
struct cro_ctx *cc;
char c;
cc = alloc_type(struct cro_ctx);
cc->xo = cc->yo = 0;
cc->scale = DEFAULT_SCALE;
cc->sheets = NULL;
cc->n_sheets = 0;
cc->output_name = NULL;
while ((c = getopt(argc, argv, "o:s:")) != EOF)
switch (c) {
case 'o':
cc->output_name = optarg;
break;
case 's':
cc->scale = atof(optarg) * DEFAULT_SCALE;
break;
default:
usage(*argv);
}
record_init(&cc->record, &real_cro_ops, cc);
return cc;
}
static void *cr_png_init(int argc, char *const *argv)
{
struct cro_ctx *cc;
cc = init_common(argc, argv);
/* cr_text_width needs *something* to work with */
cc->s = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 16, 16);
cc->cr = cairo_create(cc->s);
return cc;
}
static void *cr_pdf_init(int argc, char *const *argv)
{
struct cro_ctx *cc;
cc = init_common(argc, argv);
/* cr_text_width needs *something* to work with */
cc->s = cairo_pdf_surface_create(NULL, 16, 16);
cc->cr = cairo_create(cc->s);
return cc;
}
static void end_common(struct cro_ctx *cc, int *w, int *h)
{
int x, y;
cairo_surface_destroy(cc->s);
cairo_destroy(cc->cr);
record_bbox(&cc->record, &x, &y, w, h);
// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, x, y);
cc->xo = -cd(cc, x);
cc->yo = -cd(cc, y);
*w = cd(cc, *w);
*h = cd(cc, *h);
// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, x, y);
}
static void cr_png_end(void *ctx)
{
struct cro_ctx *cc = ctx;
int w, h;
end_common(cc, &w, &h);
cc->s = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h);
cc->cr = cairo_create(cc->s);
set_color(cc->cr, COLOR_WHITE);
cairo_paint(cc->cr);
cairo_select_font_face(cc->cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_line_width(cc->cr, 2);
record_replay(&cc->record);
record_destroy(&cc->record);
if (cc->output_name)
cairo_surface_write_to_png(cc->s, cc->output_name);
}
static void cr_pdf_new_sheet(void *ctx)
{
struct cro_ctx *cc = ctx;
cc->n_sheets++;
cc->sheets = realloc(cc->sheets, sizeof(struct record) * cc->n_sheets);
if (!cc->sheets) {
perror("realloc");
exit(1);
}
cc->sheets[cc->n_sheets - 1] = cc->record;
record_wipe(&cc->record);
}
static void cr_pdf_end(void *ctx)
{
struct cro_ctx *cc = ctx;
int w, h;
unsigned i;
end_common(cc, &w, &h);
cc->s = cairo_pdf_surface_create(cc->output_name, w, h);
cc->cr = cairo_create(cc->s);
cairo_select_font_face(cc->cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_line_width(cc->cr, 2);
for (i = 0; i != cc->n_sheets; i++) {
set_color(cc->cr, COLOR_WHITE);
cairo_paint(cc->cr);
record_replay(cc->sheets + i);
record_destroy(cc->sheets + i);
cairo_show_page(cc->cr);
}
record_replay(&cc->record);
record_destroy(&cc->record);
cairo_show_page(cc->cr);
cairo_surface_destroy(cc->s);
cairo_destroy(cc->cr);
}
uint32_t *cro_img_end(void *ctx, int *w, int *h, int *stride)
{
struct cro_ctx *cc = ctx;
uint32_t *data;
end_common(cc, w, h);
*stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, *w);
data = alloc_size(*stride * *h);
cc->s = cairo_image_surface_create_for_data((unsigned char *) data,
CAIRO_FORMAT_RGB24, *w, *h, *stride);
cc->cr = cairo_create(cc->s);
set_color(cc->cr, COLOR_WHITE);
cairo_paint(cc->cr);
cairo_select_font_face(cc->cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
CAIRO_FONT_WEIGHT_BOLD);
cairo_set_line_width(cc->cr, 2);
record_replay(&cc->record);
record_destroy(&cc->record);
return data;
}
void cro_img_write(void *ctx, const char *name)
{
struct cro_ctx *cc = ctx;
cairo_surface_write_to_png(cc->s, name);
}
/* ----- Operations -------------------------------------------------------- */
const struct gfx_ops cro_png_ops = {
.name = "png",
.line = record_line,
.poly = record_poly,
.circ = record_circ,
.arc = record_arc,
.text = record_text,
.text_width = cr_text_width,
.init = cr_png_init,
.end = cr_png_end,
};
const struct gfx_ops cro_pdf_ops = {
.name = "pdf",
.line = record_line,
.poly = record_poly,
.circ = record_circ,
.arc = record_arc,
.text = record_text,
.text_width = cr_text_width,
.init = cr_pdf_init,
.new_sheet = cr_pdf_new_sheet,
.end = cr_pdf_end,
};

31
eeshow/cro.h Normal file
View File

@ -0,0 +1,31 @@
/*
* cro.h - Cairo graphics back-end
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 CRO_H
#define CRO_H
#include <stdint.h>
#include "gfx.h"
extern const struct gfx_ops cro_png_ops;
extern const struct gfx_ops cro_pdf_ops;
#define cro_img_ops cro_png_ops /* just don't call cro_img_ops.end */
uint32_t *cro_img_end(void *ctx, int *w, int *h, int *stride);
void cro_img_write(void *ctx, const char *name);
#endif /* !CRO_H */

279
eeshow/diff.c Normal file
View File

@ -0,0 +1,279 @@
/*
* diff.c - Schematics difference
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include "util.h"
#include "main.h"
#include "cro.h"
#include "sch.h"
#include "lib.h"
#include "diff.h"
#define DEFAULT_FRAME_RADIUS 30
struct area {
int xa, ya, xb, yb;
struct area *next;
};
struct diff {
void *cr_ctx;
uint32_t *new_img;
int w, h, stride;
const char *output_name;
int frame_radius;
struct area *areas;
};
/* ----- Wrappers ---------------------------------------------------------- */
static void diff_line(void *ctx, int sx, int sy, int ex, int ey,
int color, unsigned layer)
{
const struct diff *diff = ctx;
cro_img_ops.line(diff->cr_ctx, sx, sy, ex, ey, color, layer);
}
static void diff_poly(void *ctx,
int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer)
{
const struct diff *diff = ctx;
cro_img_ops.poly(diff->cr_ctx, points, x, y, color, fill_color, layer);
}
static void diff_circ(void *ctx, int x, int y, int r,
int color, int fill_color, unsigned layer)
{
const struct diff *diff = ctx;
cro_img_ops.circ(diff->cr_ctx, x, y, r, color, fill_color, layer);
}
static void diff_arc(void *ctx, int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer)
{
const struct diff *diff = ctx;
cro_img_ops.arc(diff->cr_ctx, x, y, r, sa, ea,
color, fill_color, layer);
}
static void diff_text(void *ctx, int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer)
{
const struct diff *diff = ctx;
cro_img_ops.text(diff->cr_ctx, x, y, s, size, align, rot,
color, layer);
}
static unsigned diff_text_width(void *ctx, const char *s, unsigned size)
{
const struct diff *diff = ctx;
return cro_img_ops.text_width(diff->cr_ctx, s, size);
}
/* ----- Initialization and termination ------------------------------------ */
static void *diff_init(int argc, char *const *argv)
{
struct diff *diff;
char c;
int arg;
struct sch_ctx new_sch;
struct lib new_lib;
diff = alloc_type(struct diff);
diff->areas = NULL;
sch_init(&new_sch, 0);
lib_init(&new_lib);
diff->output_name = NULL;
diff->frame_radius = DEFAULT_FRAME_RADIUS;
while ((c = getopt(argc, argv, "o:s:")) != EOF)
switch (c) {
case 'o':
diff->output_name = optarg;
break;
case 's':
/* for cro_png */
break;
default:
usage(*argv);
}
if (argc - optind < 1)
usage(*argv);
for (arg = optind; arg != argc - 1; arg++)
lib_parse(&new_lib, argv[arg]);
sch_parse(&new_sch, argv[argc - 1], &new_lib);
optind = 0;
gfx_init(&cro_img_ops, argc, argv);
diff->cr_ctx = gfx_ctx;
sch_render(new_sch.sheets);
diff->new_img = cro_img_end(gfx_ctx,
&diff->w, &diff->h, &diff->stride);
optind = 0;
diff->cr_ctx = cro_img_ops.init(argc, argv);
return diff;
}
/* steal from schhist/ppmdiff.c */
#define ONLY_OLD 0xff0000
#define ONLY_NEW 0x00d000
#define BOTH 0x707070
#define AREA_FILL 0xffffc8
static void mark_area(struct diff *diff, int x, int y)
{
struct area *area;
for (area = diff->areas; area; area = area->next)
if (x >= area->xa && x <= area->xb &&
y >= area->ya && y <= area->yb) {
if (area->xa > x - diff->frame_radius)
area->xa = x - diff->frame_radius;
if (area->xb < x + diff->frame_radius)
area->xb = x + diff->frame_radius;
if (area->ya > y - diff->frame_radius)
area->ya = y - diff->frame_radius;
if (area->yb < y + diff->frame_radius)
area->yb = y + diff->frame_radius;
return;
}
area = alloc_type(struct area);
area->xa = x - diff->frame_radius;
area->xb = x + diff->frame_radius;
area->ya = y - diff->frame_radius;
area->yb = y + diff->frame_radius;
area->next = diff->areas;
diff->areas = area;
}
#define MASK 0xffffff
static void differences(struct diff *diff, uint32_t *a, const uint32_t *b)
{
int x, y;
unsigned skip = diff->w * 4 - diff->stride;
for (y = 0; y != diff->h; y++) {
for (x = 0; x != diff->w; x++) {
if (!((*a ^ *b) & MASK)) {
*a = ((*a >> 3) & 0x1f1f1f) | 0xe0e0e0;
// *a = ((*a >> 2) & 0x3f3f3f) | 0xc0c0c0;
} else {
mark_area(diff, x, y);
//fprintf(stderr, "0x%06x 0x%06x", *a, *b);
*a = (*a & MASK) == MASK ? ONLY_NEW :
(*b & MASK) == MASK ? ONLY_OLD : BOTH;
//fprintf(stderr, "-> 0x%06x\n", *a);
}
a++;
b++;
}
a += skip;
b += skip;
}
}
static void show_areas(struct diff *diff, uint32_t *a)
{
const struct area *area;
uint32_t *p;
int x, y;
for (area = diff->areas; area; area = area->next)
for (y = area->ya; y != area->yb; y++) {
if (y < 0 || y >= diff->h)
continue;
p = a + y * (diff->stride >> 2);
for (x = area->xa; x != area->xb; x++) {
if (x >= 0 && x < diff->w &&
(p[x] & MASK) == MASK)
p[x] = AREA_FILL;
}
}
}
static void diff_end(void *ctx)
{
struct diff *diff = ctx;
uint32_t *old_img;
int w, h, stride;
old_img = cro_img_end(diff->cr_ctx, &w, &h, &stride);
if (diff->w != w || diff->h != h) {
fprintf(stderr, "%d x %d vs. %d x %d image\n",
w, h, diff->w, diff->h);
exit(1);
}
differences(diff, old_img, diff->new_img);
show_areas(diff, old_img);
if (diff->output_name)
cro_img_write(diff->cr_ctx, diff->output_name);
}
/* ----- Operations -------------------------------------------------------- */
const struct gfx_ops diff_ops = {
.name = "diff",
.line = diff_line,
.poly = diff_poly,
.circ = diff_circ,
.arc = diff_arc,
.text = diff_text,
.text_width = diff_text_width,
.init = diff_init,
.end = diff_end,
};

22
eeshow/diff.h Normal file
View File

@ -0,0 +1,22 @@
/*
* diff.h - Schematics difference
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 DIFF_H
#define DIFF_H
#include "gfx.h"
extern const struct gfx_ops diff_ops;
#endif /* !DIFF_H */

463
eeshow/dwg.c Normal file
View File

@ -0,0 +1,463 @@
/*
* dwg.c - Complex drawing functions
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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.
*/
#define _GNU_SOURCE /* for asprintf */
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "util.h"
#include "misc.h"
#include "style.h"
#include "text.h"
#include "gfx.h"
#include "dwg.h"
/* ----- Labels ------------------------------------------------------------ */
enum box_type { // ___
box_simple, // [___]
box_left, // <___]
box_right, // [___>
box_both, // <___>
};
static enum box_type flip_box(enum box_type box)
{
switch (box) {
case box_simple:
return box_simple;
case box_left:
return box_right;
case box_right:
return box_left;
case box_both:
return box_both;
default:
abort();
}
}
void dwg_label(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape)
{
struct text txt = {
.s = s,
.size = dim,
.x = x,
.y = y,
.rot = 0,
.hor = 0,
.vert = text_min,
};
int dx = 0, dy = 0;
switch (dir) {
case 0: /* right */
txt.rot = 0;
txt.hor = text_min;
dy = 1;
break;
case 1: /* up */
txt.rot = 90;
txt.hor = text_min;
dx = -1;
break;
case 2: /* left */
txt.rot = 0;
txt.hor = text_max;
dy = 1;
break;
case 3: /* down */
txt.rot = 90;
txt.hor = text_max;
dx = -1;
break;
default:
assert(0);
}
txt.y -= dy * LABEL_OFFSET;
txt.x += dx * LABEL_OFFSET;
text_fig(&txt, COLOR_LABEL, LAYER_LABEL);
}
void dwg_glabel(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape)
{
struct text txt = {
.s = s,
.size = dim,
.x = x,
.y = y,
.rot = 0,
.hor = 0,
.vert = text_mid,
};
int n = 6;
int vx[7];
int vy[7];
int half = (dim >> 1) + GLABEL_OFFSET;
enum box_type box;
int dx, shift_flat, shift_tip;
bool anchor_right = 1;
char *tag;
switch (shape) {
case dwg_unspec:
box = box_simple;
break;
case dwg_in:
box = box_right;
break;
case dwg_out:
box = box_left;
break;
case dwg_bidir:
box = box_both;
break;
default:
assert(0);
}
switch (dir) {
case 0: /* left */
txt.rot = 0;
txt.hor = text_max;
dx = -1;
break;
case 1: /* up */
txt.rot = 90;
txt.hor = text_min;
dx = 1;
box = flip_box(box);
anchor_right = !anchor_right;
break;
case 2: /* right */
txt.rot = 0;
txt.hor = text_min;
dx = 1;
box = flip_box(box);
anchor_right = !anchor_right;
break;
case 3: /* down */
txt.rot = 90;
txt.hor = text_max;
dx = -1;
break;
default:
assert(0);
}
shift_flat = dx * GLABEL_OFFSET;
shift_tip = dx * (GLABEL_OFFSET + half);
switch (box) {
case box_simple:
n = 5;
text_shift(&txt, txt.hor, text_mid, shift_flat, 0);
text_rel(&txt, text_min, text_min,
-GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
text_rel(&txt, text_max, text_min,
GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
text_rel(&txt, text_max, text_max,
GLABEL_OFFSET, -GLABEL_OFFSET, vx + 3, vy + 3);
text_rel(&txt, text_min, text_max,
-GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
break;
case box_right:
text_shift(&txt, txt.hor, text_mid,
anchor_right ? shift_tip : shift_flat, 0);
text_rel(&txt, text_min, text_min,
-GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
text_rel(&txt, text_max, text_min,
GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
text_rel(&txt, text_max, text_mid, GLABEL_OFFSET + half, 0,
vx + 3, vy + 3);
text_rel(&txt, text_max, text_max,
GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
text_rel(&txt, text_min, text_max,
-GLABEL_OFFSET, -GLABEL_OFFSET, vx + 5, vy + 5);
break;
case box_left:
text_shift(&txt, txt.hor, text_mid,
anchor_right ? shift_flat : shift_tip, 0);
text_rel(&txt, text_min, text_min,
-GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
text_rel(&txt, text_max, text_min,
GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
text_rel(&txt, text_max, text_max,
GLABEL_OFFSET, -GLABEL_OFFSET, vx + 3, vy + 3);
text_rel(&txt, text_min, text_max,
-GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
text_rel(&txt, text_min, text_mid, -GLABEL_OFFSET- half, 0,
vx + 5, vy + 5);
break;
case box_both:
n = 7;
text_shift(&txt, txt.hor, text_mid, shift_tip, 0);
text_rel(&txt, text_min, text_min,
-GLABEL_OFFSET, GLABEL_OFFSET, vx + 1, vy + 1);
text_rel(&txt, text_max, text_min,
GLABEL_OFFSET, GLABEL_OFFSET, vx + 2, vy + 2);
text_rel(&txt, text_max, text_mid, GLABEL_OFFSET + half, 0,
vx + 3, vy + 3);
text_rel(&txt, text_max, text_max,
GLABEL_OFFSET, -GLABEL_OFFSET, vx + 4, vy + 4);
text_rel(&txt, text_min, text_max,
-GLABEL_OFFSET, -GLABEL_OFFSET, vx + 5, vy + 5);
text_rel(&txt, text_min, text_mid, -GLABEL_OFFSET- half, 0,
vx + 6, vy + 6);
break;
default:
assert(0);
}
text_fig(&txt, COLOR_GLABEL, LAYER_GLABEL);
vx[0] = vx[n - 1];
vy[0] = vy[n - 1];
gfx_poly(n, vx, vy, COLOR_GLABEL, COLOR_NONE, LAYER_GLABEL);
if (asprintf(&tag, "G:%s", s)) {}
gfx_tag(tag, n, vx, vy);
}
static int make_box(enum box_type box, int h, int *vx, int *vy)
{
int r = h / 2;
switch (box) {
case box_simple:
vx[0] = 0;
vy[0] = -r;
vx[1] = 2 * r;
vy[1] = -r;
vx[2] = 2 * r;
vy[2] = r;
vx[3] = 0;
vy[3] = r;
return 4;
case box_right:
vx[0] = 0;
vy[0] = -r;
vx[1] = r;
vy[1] = -r;
vx[2] = 2 * r;
vy[2] = 0;
vx[3] = r;
vy[3] = r;
vx[4] = 0;
vy[4] = r;
return 5;
case box_left:
vx[0] = r;
vy[0] = -r;
vx[1] = 2 * r;
vy[1] = -r;
vx[2] = 2 * r;
vy[2] = r;
vx[3] = r;
vy[3] = r;
vx[4] = 0;
vy[4] = 0;
return 5;
case box_both:
vx[0] = 0;
vy[0] = 0;
vx[1] = r;
vy[1] = -r;
vx[2] = 2 * r;
vy[2] = 0;
vx[3] = r;
vy[3] = r;
return 4;
default:
assert(0);
}
}
void dwg_hlabel(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape)
{
struct text txt = {
.s = s,
.size = dim,
.x = x,
.y = y,
.rot = 0,
.hor = 0,
.vert = text_mid,
};
int vx[6], vy[6];
int rot;
int n, i;
switch (shape) {
case dwg_unspec:
n = make_box(box_simple, dim, vx, vy);
break;
case dwg_in:
n = make_box(box_left, dim, vx, vy);
break;
case dwg_out:
n = make_box(box_right, dim, vx, vy);
break;
case dwg_bidir:
n = make_box(box_both, dim, vx, vy);
break;
default:
assert(0);
}
switch (dir) {
case 0: /* right */
rot = 180;
txt.hor = text_max;
break;
case 1: /* up */
rot = 90;
txt.hor = text_min;
break;
case 2: /* left */
rot = 0;
txt.hor = text_min;
break;
case 3: /* down */
rot = 270;
txt.hor = text_max;
break;
default:
assert(0);
}
txt.x += rx((1 + HLABEL_OFFSET_F) * dim, 0, rot);
txt.y += ry((1 + HLABEL_OFFSET_F) * dim, 0, rot);
for (i = 0; i != n; i++) {
int tmp;
tmp = x + rx(vx[i], vy[i], rot);
vy[i] = y + ry(vx[i], vy[i], rot);
vx[i] = tmp;
}
vx[n] = vx[0];
vy[n] = vy[0];
txt.rot = rot % 180;
text_fig(&txt, COLOR_HLABEL, LAYER_HLABEL);
gfx_poly(n + 1, vx, vy, COLOR_HLABEL, COLOR_NONE, LAYER_HLABEL);
}
/* ----- Text -------------------------------------------------------------- */
void dwg_text(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape)
{
struct text txt = {
.s = s,
.size = dim,
.x = x,
.y = y,
.rot = 0,
.hor = text_min,
.vert = text_min,
};
switch (dir) {
case 0: /* right */
break;
case 1: /* up */
text_rot(&txt, 90);
break;
case 2: /* left */
txt.hor = text_max;
break;
case 3: /* down */
text_rot(&txt, 90);
txt.hor = text_max;
break;
default:
assert(2 + 2 == 5);
}
text_fig(&txt, COLOR_TEXT, LAYER_TEXT);
}
/* ----- Connections ------------------------------------------------------- */
void dwg_junction(int x, int y)
{
gfx_circ(x, y, JUNCTION_R, COLOR_NONE, COLOR_WIRE, LAYER_WIRES);
}
void dwg_noconn(int x, int y)
{
int vx[2] = { x - NOCONN_LEN, x + NOCONN_LEN };
int vy[2] = { y - NOCONN_LEN, y + NOCONN_LEN };
gfx_poly(2, vx, vy, COLOR_NOCONN, COLOR_NONE, LAYER_NOCONN);
swap(vy[0], vy[1]);
gfx_poly(2, vx, vy, COLOR_NOCONN, COLOR_NONE, LAYER_NOCONN);
}
/* ----- Lines ------------------------------------------------------------- */
/*
* We can't use gfx_poly because lines are dashed and we don't have that
* property at the gfx_poly API.
*/
void dwg_line(int sx, int sy, int ex, int ey)
{
gfx_line(sx, sy, ex, ey, COLOR_SHEET_DWG, LAYER_LINES);
}
/* ----- Wires and busses -------------------------------------------------- */
void dwg_wire(int sx, int sy, int ex, int ey)
{
int vx[] = { sx, ex };
int vy[] = { sy, ey };
// WIDTH_WIRE
gfx_poly(2, vx, vy, COLOR_WIRE, COLOR_NONE, LAYER_WIRES);
}
void dwg_bus(int sx, int sy, int ex, int ey)
{
int vx[] = { sx, ex };
int vy[] = { sy, ey };
// WIDTH_BUS
gfx_poly(2, vx, vy, COLOR_BUS, COLOR_NONE, LAYER_BUSSES);
}

46
eeshow/dwg.h Normal file
View File

@ -0,0 +1,46 @@
/*
* dwg.h - Complex drawing functions
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 DWG_H
#define DWG_H
#include "fig.h"
enum dwg_shape {
dwg_unspec, // UnSpc
dwg_in, // Input
dwg_out, // Output
dwg_tri, // 3State
dwg_bidir, // Bidirectional
};
void dwg_label(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape);
void dwg_hlabel(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape);
void dwg_glabel(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape);
void dwg_text(int x, int y, const char *s, int dir, int dim,
enum dwg_shape shape);
void dwg_junction(int x, int y);
void dwg_noconn(int x, int y);
void dwg_line(int sx, int sy, int ex, int ey);
void dwg_wire(int sx, int sy, int ex, int ey);
void dwg_bus(int sx, int sy, int ex, int ey);
#endif /* !DWG_H */

293
eeshow/fig.c Normal file
View File

@ -0,0 +1,293 @@
/*
* fig.c - Generate FIG output for Eeschema items
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "util.h"
#include "style.h"
#include "text.h"
#include "main.h"
#include "fig.h"
/*
* FIG works with 1/1200 in
* KiCad works with mil
* 1 point = 1/72 in
*/
static inline int cx(int x)
{
return x * 1200 / 1000;
}
static inline int cy(int y)
{
return y * 1200 / 1000;
}
static inline float pt(int x)
{
return cx(x) * 72 * 1.5 / 1200.0;
}
/* ----- Schematics items -------------------------------------------------- */
static void fig_line(void *ctx, int sx, int sy, int ex, int ey,
int color, unsigned layer)
{
// TypeStyle FillCol AreaFil Cap FwdAr
// SubTy Color Pen StyleV Rad BwdAr
// Thick Depth Join Points
printf("2 1 2 %d %d 7 %d -1 -1 3.0 1 1 -1 0 0 2\n",
WIDTH_LINE, color, layer);
printf("\t%d %d %d %d\n", cx(sx), cy(sy), cx(ex), cy(ey));
}
/* ----- General items ----------------------------------------------------- */
static void fig_rect(void *ctx, int sx, int sy, int ex, int ey,
int color, int fill_color, unsigned layer)
{
// Type Thick Depth StyleV Rad
// SubTy Color Pen Join FwdAr
// Style FillCol AreaFil Cap BwdAr
printf("2 2 0 %d %d %d %d -1 %d 0.0 1 1 -1 0 0 5\n",
color == -1 ? 0 : WIDTH_COMP_DWG, color, fill_color, layer,
fill_color == -1 ? -1 : 20);
printf("\t%d %d %d %d %d %d %d %d %d %d\n",
cx(sx), cy(sy), cx(ex), cy(sy), cx(ex), cy(ey), cx(sx), cy(ey),
cx(sx), cy(sy));
}
static void fig_poly(void *ctx,
int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer)
{
int i;
char ch = '\t';
// Type Thick Depth StyleV Rad
// SubTy Color Pen Join FwdAr
// Style FillCol AreaFil Cap BwdAr
printf("2 1 0 %d %d %d %d -1 %d 0.0 1 1 -1 0 0 %d\n",
color == -1 ? 0 : WIDTH_COMP_DWG, color, fill_color, layer,
fill_color == -1 ? -1 : 20, points);
for (i = 0; i != points; i++) {
printf("%c%d %d", ch, cx(x[i]), cy(y[i]));
ch = ' ';
}
printf("\n");
}
static void fig_circ(void *ctx, int x, int y, int r,
int color, int fill_color, unsigned layer)
{
// Type Thick Depth StyleV Cx Rx Sx Ex
// SubTy Color Pen Dir Cy Ry Sy Ey
// Style FillCol AreaFil Angle
printf("1 3 0 %d %d %d %d -1 %d 0.0 1 0.0 %d %d %d %d %d %d %d %d\n",
color == -1 ? 0 : WIDTH_COMP_DWG, color, fill_color, layer,
fill_color == -1 ? -1 : 20,
cx(x), cy(y), r, r,
cx(x), cy(y), cx(x) + r, cy(y));
}
static int ax(int x, int y, int r, int angle)
{
float a = angle / 180.0 * M_PI;
return cx(x + r * cos(a));
}
static int ay(int x, int y, int r, int angle)
{
float a = angle / 180.0 * M_PI;
return cy(y - r * sin(a));
}
static void fig_arc(void *ctx, int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer)
{
int ma = (sa + ea) / 2;
// Type Thick Depth StyleV FwdAr
// SubTy Color Pen Cap BwdAr
// Style FillCol AreaFil Dir points
printf("5 1 0 %d %d %d %d -1 %d 0.0 1 1 0 0 %d %d %d %d %d %d %d %d\n",
color == -1 ? 0 : WIDTH_COMP_DWG, color, fill_color, layer,
fill_color == -1 ? -1 : 20,
cx(x), cy(y),
ax(x, y, r, sa), ay(x, y, r, sa),
ax(x, y, r, ma), ay(x, y, r, ma),
ax(x, y, r, ea), ay(x, y, r, ea));
}
static void fig_tag(void *ctx, const char *s,
int points, const int x[points], const int y[points])
{
printf("# href=\"%s\" alt=\"\"\n", s);
fig_poly(ctx, points, x, y, COLOR_NONE, COLOR_NONE, 999);
}
static void fig_text(void *ctx, int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer)
{
// Type Depth FontSiz Height
// Just Pen Angle Length
// Color Font Flags X Y
printf("4 %u %d %d -1 %d %f %f 4 0.0 0.0 %d %d %s\\001\n",
align, color, layer, FONT_HELVETICA_BOLD,
pt(size), rot / 180.0 * M_PI, cx(x), cy(y), s);
}
static unsigned fig_text_width(void *ctx, const char *s, unsigned size)
{
/*
* Note that we stretch the text size, so the ratio is larger than
* expressed here.
*/
return strlen(s) * size * 1.0;
}
/* ----- FIG file header --------------------------------------------------- */
static void fig_header(void)
{
printf("#FIG 3.2\n");
printf("Landscape\n");
printf("Center\n");
printf("Metric\n");
printf("A4\n");
printf("100.00\n");
printf("Single\n");
printf("-2\n");
printf("1200 2\n");
/* User32, COLOR_DARK_YELLOW */
printf("0 32 #848400\n");
}
static bool apply_vars(char *buf, int n_vars, const char **vars)
{
char *p;
const char **var, *eq;
int var_len, value_len;
p = strchr(buf, '<');
if (!p)
return 0;
for (var = vars; var != vars + n_vars; var++) {
eq = strchr(*var, '=');
assert(eq);
var_len = eq - *var;
if (strncmp(p + 1, *var, var_len))
continue;
value_len = strlen(eq + 1);
memmove(p + value_len, p + var_len + 2,
strlen(p + var_len + 2) + 1);
memcpy(p, eq + 1, value_len);
return 1;
}
return 0;
}
static void *fig_init(int argc, char *const *argv)
{
const char *template = NULL;
const char **vars = NULL;
int n_vars = 0;
char c;
int arg;
FILE *file;
char buf[1000];
while ((c = getopt(argc, argv, "t:")) != EOF)
switch (c) {
case 't':
template = optarg;
break;
default:
usage(*argv);
}
for (arg = optind; arg != argc; arg++) {
if (!strchr(argv[arg], '='))
usage(*argv);
n_vars++;
vars = realloc(vars, sizeof(const char *) * n_vars);
vars[n_vars - 1] = argv[arg];
}
if (!template) {
fig_header();
return NULL;
}
file = fopen(template, "r");
if (!file) {
perror(template);
exit(1);
}
while (fgets(buf, sizeof(buf), file)) {
while (apply_vars(buf, n_vars, vars));
printf("%s", buf);
}
fclose(file);
return NULL;
}
/* ----- Operations -------------------------------------------------------- */
const struct gfx_ops fig_ops = {
.name = "fig",
.line = fig_line,
.rect = fig_rect,
.poly = fig_poly,
.circ = fig_circ,
.arc = fig_arc,
.text = fig_text,
.tag = fig_tag,
.text_width = fig_text_width,
.init = fig_init,
};

22
eeshow/fig.h Normal file
View File

@ -0,0 +1,22 @@
/*
* fig.h - Generate FIG output for Eeschema items
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 FIG_H
#define FIG_H
#include "gfx.h"
extern const struct gfx_ops fig_ops;
#endif /* !FIG_H */

76
eeshow/file.c Normal file
View File

@ -0,0 +1,76 @@
/*
* file.c - Open and read a file
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "main.h"
#include "git-file.h"
#include "file.h"
bool file_cat(void *user, const char *line)
{
printf("%s\n", line);
return 1;
}
static void read_from_file(FILE *file,
bool (*parse)(void *user, const char *line), void *user)
{
char buf[1000];
char *nl;
while (fgets(buf, sizeof(buf), file)) {
nl = strchr(buf, '\n');
if (nl)
*nl = 0;
if (!parse(user, buf))
break;
}
}
void file_read(const char *name, bool (*parse)(void *user, const char *line),
void *user)
{
FILE *file;
char *colon, *tmp;
file = fopen(name, "r");
if (file) {
if (verbose)
fprintf(stderr, "reading %s\n", name);
read_from_file(file, parse, user);
fclose(file);
return;
}
if (verbose)
perror(name);
colon = strchr(name, ':');
if (!colon) {
if (!verbose)
perror(name);
exit(1);
}
tmp = stralloc(name);
tmp[colon - name] = 0;
git_read(tmp, colon + 1, parse, user);
free(tmp);
}

22
eeshow/file.h Normal file
View File

@ -0,0 +1,22 @@
/*
* file.h - Open and read a file
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 FILE_H
#define FILE_H
#include <stdbool.h>
bool file_cat(void *user, const char *line);
void file_read(const char *name, bool (*parse)(void *user, const char *line),
void *user);
#endif /* !FILE_H */

120
eeshow/gfx.c Normal file
View File

@ -0,0 +1,120 @@
/*
* gfx.c - Generate graphical output for Eeschema items
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stdbool.h>
#include "style.h"
#include "text.h"
#include "gfx.h"
void *gfx_ctx;
static const struct gfx_ops *gfx_ops;
void gfx_line(int sx, int sy, int ex, int ey, int color, unsigned layer)
{
if (gfx_ops->line) {
gfx_ops->line(gfx_ctx, sx, sy, ex, ey, color, layer);
return;
}
int vx[] = { sx, ex };
int vy[] = { sy, ey };
gfx_poly(2, vx, vy, color, COLOR_NONE, layer);
}
void gfx_rect(int sx, int sy, int ex, int ey,
int color, int fill_color, unsigned layer)
{
if (gfx_ops->rect) {
gfx_ops->rect(gfx_ctx, sx, sy, ex, ey,
color, fill_color, layer);
return;
}
int vx[] = { sx, ex, ex, sx, sx };
int vy[] = { sy, sy, ey, ey, sy };
gfx_poly(5, vx, vy, color, fill_color, layer);
}
void gfx_poly(int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer)
{
gfx_ops->poly(gfx_ctx, points, x, y, color, fill_color, layer);
}
void gfx_circ(int x, int y, int r, int color, int fill_color, unsigned layer)
{
gfx_ops->circ(gfx_ctx, x, y, r, color, fill_color, layer);
}
void gfx_arc(int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer)
{
gfx_ops->arc(gfx_ctx, x, y, r, sa, ea, color, fill_color, layer);
}
void gfx_text(int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer)
{
gfx_ops->text(gfx_ctx, x, y, s, size, align, rot, color, layer);
}
void gfx_tag(const char *s,
unsigned points, const int x[points], int const y[points])
{
if (gfx_ops->tag)
gfx_ops->tag(gfx_ctx, s, points, x, y);
}
unsigned gfx_text_width(const char *s, unsigned size)
{
return gfx_ops->text_width(gfx_ctx, s, size);
}
void gfx_init(const struct gfx_ops *ops, int argc, char *const *argv)
{
gfx_ctx = ops->init(argc, argv);
gfx_ops = ops;
}
void gfx_new_sheet(void)
{
if (gfx_ops->new_sheet)
gfx_ops->new_sheet(gfx_ctx);
}
bool gfx_multi_sheet(void)
{
return !!gfx_ops->new_sheet;
}
void gfx_end(void)
{
if (gfx_ops->end)
gfx_ops->end(gfx_ctx);
}

72
eeshow/gfx.h Normal file
View File

@ -0,0 +1,72 @@
/*
* gfx.h - Generate graphical output for Eeschema items
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 GFX_H
#define GFX_H
#include <stdbool.h>
#include "text.h"
struct gfx_ops {
const char *name;
void (*line)(void *ctx, int sx, int sy, int ex, int ey,
int color, unsigned layer);
void (*rect)(void *ctx, int sx, int sy, int ex, int ey,
int color, int fill_color, unsigned layer);
void (*poly)(void *ctx,
int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer);
void (*circ)(void *ctx, int x, int y, int r,
int color, int fill_color, unsigned layer);
void (*arc)(void *ctx, int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer);
void (*text)(void *ctx, int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer);
void (*tag)(void *ctx, const char *s,
int points, const int x[points], const int y[points]);
unsigned (*text_width)(void *ctx, const char *s, unsigned size);
void *(*init)(int argc, char *const *argv);
void (*new_sheet)(void *ctx);
void (*end)(void *ctx);
};
extern void *gfx_ctx;
/* wrappers */
void gfx_line(int sx, int sy, int ex, int ey, int color, unsigned layer);
void gfx_rect(int sx, int sy, int ex, int ey,
int color, int fill_color, unsigned layer);
void gfx_poly(int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer);
void gfx_circ(int x, int y, int r, int color, int fill_color, unsigned layer);
void gfx_arc(int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer);
void gfx_text(int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer);
void gfx_tag(const char *s,
unsigned points, const int x[points], int const y[points]);
unsigned gfx_text_width(const char *s, unsigned size);
/* inititalization and termination */
void gfx_init(const struct gfx_ops *ops, int argc, char *const *argv);
void gfx_new_sheet(void);
bool gfx_multi_sheet(void);
void gfx_end(void);
#endif /* !GFX_H */

371
eeshow/git-file.c Normal file
View File

@ -0,0 +1,371 @@
/*
* git-file.c - Open and read a file from git
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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.
*/
#define _GNU_SOURCE /* for get_current_dir_name */
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <git2.h>
#include "util.h"
#include "main.h"
#include "git-file.h"
static git_repository *select_repo(const char *path)
{
git_repository *repo = NULL;
char *tmp = stralloc(path);
char *slash;
/*
* If we can't find a repo, this may be due to the file or directory
* the path points to not existing in the currently checked-out tree.
* So we trim off elements until we find a repository.
*/
while (1) {
if (verbose > 2)
fprintf(stderr, "trying \"%s\"\n", tmp);
if (!git_repository_open_ext(&repo, *tmp ? tmp : "/",
GIT_REPOSITORY_OPEN_CROSS_FS, NULL))
break;
slash = strrchr(tmp, '/');
if (!slash)
break;
*slash = 0;
}
free(tmp);
return repo;
}
static git_tree *pick_revision(git_repository *repo, const char *revision)
{
git_commit *commit;
git_object *obj;
git_tree *tree;
if (git_revparse_single(&obj, repo, revision)) {
const git_error *e = giterr_last();
fprintf(stderr, "%s: %s\n",
git_repository_path(repo), e->message);
exit(1);
}
if (git_object_type(obj) != GIT_OBJ_COMMIT) {
fprintf(stderr, "%s: not a commit\n", revision);
exit(1);
}
commit = (git_commit *) obj;
if (git_commit_tree(&tree, commit)) {
const git_error *e = giterr_last();
fprintf(stderr, "%s: %s\n", revision, e->message);
exit(1);
}
return tree;
}
static char *canonical_path_into_repo(const char *repo_dir, const char *path)
{
struct stat repo_st, path_st;
char *tmp, *tmp2, *slash, *tail, *real;
char *to;
const char *end, *from;
/* identify inode of repo root */
if (stat(repo_dir, &repo_st) < 0) {
perror(repo_dir);
exit(1);
}
if (!S_ISDIR(repo_st.st_mode)) {
fprintf(stderr, "%s: not a directory\n", repo_dir);
exit(1);
}
/* convert relative paths to absolute */
if (*path == '/') {
tmp = stralloc(path);
} else {
char *cwd = get_current_dir_name();
tmp = alloc_size(strlen(cwd) + 1 + strlen(path) + 1);
sprintf(tmp, "%s/%s", cwd, path);
free(cwd);
}
/* remove trailing / */
slash = strrchr(tmp, '/');
if (slash && slash != tmp && !slash[1])
*slash = 0;
/*
* If path does point to inexistent object, separate into the part that
* is valid on the current system and the tail containing dead things.
*/
end = tail = strchr(tmp, 0);
while (1) {
if (verbose > 2)
fprintf(stderr, "probing \"%s\" tail \"%s\"\n",
tmp, tail);
if (stat(tmp, &path_st) == 0)
break;
if (!tmp[1]) {
fprintf(stderr, "%s: cannot resolve\n", path);
exit(1);
}
slash = strrchr(tmp, '/');
if (tail != end)
tail[-1] = '/';
tail = slash + 1;
*slash = 0;
}
/* remove . and .. from tail */
if (verbose > 2)
fprintf(stderr, "input tail \"%s\"\n", tail);
from = to = tail;
while (1) {
if (!strncmp(from, "./", 2)) {
from += 2;
continue;
}
if (!strcmp(from, "."))
break;
if (strncmp(from, "../", 3) && strcmp(from, "..")) {
while (*from) {
*to++ = *from++;
if (from[-1] == '/')
break;
}
if (!*from)
break;
}
if (to == tail) {
/*
* We have something like this:
* /home/repo/dead/../../foo
*/
fprintf(stderr, "%s: can't climb out of dead path\n",
path);
exit(1);
}
/*
* We have something like
* "foo/" -> ""
* or
* "foo/bar/" -> "foo/"
* where "to" points to the end.
*/
to--;
while (to != tail && to[-1] != '/')
to--;
}
*to = 0;
if (verbose > 2)
fprintf(stderr, "output tail \"%s\"\n", tail);
/* resolve all symlinks */
real = realpath(tmp, NULL);
if (verbose > 2)
fprintf(stderr, "realpath(\"%s\") = \"%s\"\n", tmp, real);
/* append tail */
if (*tail) {
tmp2 = alloc_size(strlen(real) + 1 + strlen(tail) + 1);
sprintf(tmp2, "%s/%s", real, tail);
free(real);
} else {
tmp2 = real;
}
free(tmp);
tmp = tmp2;
if (verbose > 1)
fprintf(stderr, "full object path \"%s\"\n", tmp);
/* find which part of our path is inside the repo */
end = tail = strchr(tmp, 0);
while (1) {
if (verbose > 2)
fprintf(stderr, "trying \"%s\" tail \"%s\"\n",
tmp, tail);
if (stat(tmp, &path_st) == 0 &&
path_st.st_dev == repo_st.st_dev &&
path_st.st_ino == repo_st.st_ino)
break;
/* "this cannot happen" */
if (tail == tmp) {
fprintf(stderr,
"divergent paths:\nrepo \"%s\"\nobject \"%s\"\n",
repo_dir, tmp);
exit(1);
}
slash = strrchr(tmp, '/');
if (tail != end)
tail[-1] = '/';
tail = slash + 1;
*slash = 0;
}
if (verbose > 1)
fprintf(stderr, "path in repo \"%s\"\n", tail);
tmp2 = stralloc(tail);
free(tmp);
return tmp2;
}
static git_tree_entry *find_file(git_repository *repo, git_tree *tree,
const char *path)
{
git_tree_entry *entry;
char *repo_path = stralloc(git_repository_path(repo));
char *slash, *canon_path;
int len;
/* remove trailing / from repo_path */
slash = strrchr(repo_path, '/');
if (slash && slash != repo_path && !slash[1])
*slash = 0;
len = strlen(repo_path);
if (len >= 5 && !strcmp(repo_path + len - 5, "/.git"))
repo_path[len == 5 ? 1 : len - 5] = 0;
if (verbose > 1)
fprintf(stderr, "repo dir \"%s\"\n", repo_path);
canon_path = canonical_path_into_repo(repo_path, path);
if (git_tree_entry_bypath(&entry, tree, canon_path)) {
const git_error *e = giterr_last();
fprintf(stderr, "%s: %s\n", path, e->message);
exit(1);
}
free(canon_path);
return entry;
}
static const void *get_data(git_repository *repo, git_tree_entry *entry,
unsigned *size)
{
git_object *obj;
git_blob *blob;
if (git_tree_entry_type(entry) != GIT_OBJ_BLOB) {
fprintf(stderr, "entry is not a blob\n");
exit(1);
}
if (git_tree_entry_to_object(&obj, repo, entry)) {
const git_error *e = giterr_last();
fprintf(stderr, "%s\n", e->message);
exit(1);
}
blob = (git_blob *) obj;
*size = git_blob_rawsize(blob);
return git_blob_rawcontent(blob);
}
static bool send_line(const char *s, unsigned len,
bool (*parse)(void *user, const char *line), void *user)
{
char *tmp = alloc_size(len + 1);
bool res;
memcpy(tmp, s, len);
tmp[len] = 0;
res = parse(user, tmp);
free(tmp);
return res;
}
static void send_data(const char *data, unsigned size,
bool (*parse)(void *user, const char *line), void *user)
{
const char *end = data + size;
const char *p = data;
const char *nl;
while (p != end) {
nl = memchr(p, '\n', end - p);
if (!nl) {
send_line(p, end - p, parse, user);
return;
}
if (!send_line(p, nl - p, parse, user))
return;
p = nl + 1;
}
}
void git_read(const char *revision, const char *name,
bool (*parse)(void *user, const char *line), void *user)
{
static bool initialized = 0;
git_repository *repo;
git_tree *tree;
git_tree_entry *entry;
const void *data;
unsigned size;
if (!initialized) {
git_libgit2_init();
initialized = 1;
}
repo = select_repo(name);
if (!repo) {
fprintf(stderr, "%s:%s not found\n", revision, name);
exit(1);
}
if (verbose > 1)
fprintf(stderr, "using repository %s\n",
git_repository_path(repo));
tree = pick_revision(repo, revision);
entry = find_file(repo, tree, name);
if (verbose)
fprintf(stderr, "reading %s:%s\n", revision, name);
data = get_data(repo, entry, &size);
send_data(data, size, parse, user);
}

22
eeshow/git-file.h Normal file
View File

@ -0,0 +1,22 @@
/*
* git-file.h - Open and read a file from git
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 GIT_FILE_H
#define GIT_FILE_H
#include <stdbool.h>
void git_read(const char *revision, const char *name,
bool (*parse)(void *user, const char *line), void *user);
#endif /* !GIT_FILE_H */

268
eeshow/lib-parse.c Normal file
View File

@ -0,0 +1,268 @@
/*
* lib.c - Parse Eeschema .lib file
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 "util.h"
#include "text.h"
#include "file.h"
#include "lib.h"
/* ----- Text -------------------------------------------------------------- */
static enum text_style decode_style(const char *s)
{
if (!strcmp(s, "Normal"))
return text_normal;
assert(0);
}
/* ----- Polygons ---------------------------------------------------------- */
static bool parse_poly(struct lib_poly *poly, const char *line, int points)
{
int i, n;
poly->points = points;
poly->x = alloc_size(sizeof(int) * points);
poly->y = alloc_size(sizeof(int) * points);
for (i = 0; i != points; i++) {
if (sscanf(line, "%d %d %n",
poly->x + i, poly->y + i, &n) != 2)
return 0;
line += n;
}
if (sscanf(line, "%c", &poly->fill) != 1)
return 0;
return 1;
}
/* ----- Definitions ------------------------------------------------------- */
static bool parse_def(struct lib *lib, const char *line)
{
char *s;
char draw_num, draw_name;
unsigned name_offset;
unsigned units;
if (sscanf(line, "DEF %ms %*s %*d %u %c %c %u",
&s, &name_offset, &draw_num, &draw_name, &units) != 5)
return 0;
lib->curr_comp = alloc_type(struct comp);
if (*s == '~')
s++;
lib->curr_comp->name = s;
lib->curr_comp->units = units;
lib->curr_comp->visible = 0;
lib->curr_comp->show_pin_name = draw_name == 'Y';
lib->curr_comp->show_pin_num = draw_num == 'Y';
lib->curr_comp->name_offset = name_offset;
lib->curr_comp->objs = NULL;
lib->next_obj = &lib->curr_comp->objs;
lib->curr_comp->next = NULL;
*lib->next_comp = lib->curr_comp;
lib->next_comp = &lib->curr_comp->next;
return 1;
}
/* ----- Arcs -------------------------------------------------------------- */
static bool parse_arc(struct lib_obj *obj, const char *line)
{
struct lib_arc *arc = &obj->u.arc;
int a1, a2;
if (sscanf(line, "A %d %d %d %d %d %u %u %u %c",
&arc->x, &arc->y, &arc->r, &a1, &a2, &obj->unit, &obj->convert,
&arc->thick, &arc->fill) != 9)
return 0;
/*
* KiCad arcs can be clockwise or counter-clockwise. They must always
* be smaller than 180 degrees.
*/
while (a1 < 0)
a1 += 3600;
while (a2 < 0)
a2 += 3600;
a1 %= 3600;
a2 %= 3600;
if (a2 < a1)
a2 += 3600;
assert(a2 - a1 != 1800);
if (a2 - a1 > 1800)
swap(a1, a2);
arc->start_a = (a1 % 3600) / 10;
arc->end_a = (a2 % 3600) / 10;
return 1;
}
/* ----- Library parser ---------------------------------------------------- */
static bool lib_parse_line(void *user, const char *line)
{
struct lib *lib = user;
int n = 0;
unsigned points;
struct lib_obj *obj;
char *style;
unsigned zero1, zero2;
char vis;
lib->lineno++;
switch (lib->state) {
case lib_skip:
if (parse_def(lib, line)) {
lib->state = lib_def;
return 1;
}
return 1;
case lib_def:
if (sscanf(line, "DRAW%n", &n) == 0 && n) {
lib->state = lib_draw;
return 1;
}
if (sscanf(line, "F%d \"\" %*d %*d %*d %*c %c", &n, &vis) == 2
|| sscanf(line, "F%d \"%*[^\"]\" %*d %*d %*d %*c %c",
&n, &vis) == 2) {
if (vis == 'V')
lib->curr_comp->visible |= 1 << n;
return 1;
}
/* @@@ explicitly ignore FPLIST */
return 1;
case lib_draw:
if (sscanf(line, "ENDDRAW%n", &n) == 0 && n) {
lib->state = lib_skip;
return 1;
}
obj = alloc_type(struct lib_obj);
obj->next = NULL;
*lib->next_obj = obj;
lib->next_obj = &obj->next;
if (sscanf(line, "P %u %u %u %u %n",
&points, &obj->unit, &obj->convert, &obj->u.poly.thick,
&n) == 4) {
obj->type = lib_obj_poly;
if (parse_poly(&obj->u.poly, line + n, points))
return 1;
break;
}
if (sscanf(line, "S %d %d %d %d %u %u %d %c",
&obj->u.rect.sx, &obj->u.rect.sy, &obj->u.rect.ex,
&obj->u.rect.ey, &obj->unit, &obj->convert,
&obj->u.rect.thick, &obj->u.rect.fill) == 8) {
obj->type = lib_obj_rect;
return 1;
}
if (sscanf(line, "C %d %d %d %u %u %d %c",
&obj->u.circ.x, &obj->u.circ.y, &obj->u.circ.r,
&obj->unit, &obj->convert, &obj->u.circ.thick,
&obj->u.circ.fill) == 7) {
obj->type = lib_obj_circ;
return 1;
}
if (parse_arc(obj, line)) {
obj->type = lib_obj_arc;
return 1;
}
n = sscanf(line,
"T %d %d %d %d %u %u %u \"%m[^\"]\" %ms %u %c %c",
&obj->u.text.orient, &obj->u.text.x, &obj->u.text.y,
&obj->u.text.dim, &zero1, &obj->unit, &obj->convert,
&obj->u.text.s, &style, &zero2,
&obj->u.text.hor_align, &obj->u.text.vert_align);
if (n != 12) {
n = sscanf(line,
"T %d %d %d %d %u %u %u %ms %ms %u %c %c",
&obj->u.text.orient, &obj->u.text.x, &obj->u.text.y,
&obj->u.text.dim, &zero1, &obj->unit, &obj->convert,
&obj->u.text.s, &style, &zero2,
&obj->u.text.hor_align, &obj->u.text.vert_align);
while (n == 12) {
char *tilde;
tilde = strchr(obj->u.text.s, '~');
if (!tilde)
break;
*tilde = ' ';
}
}
/*
* zero2 seems to be the font style: 0 = normal, 1 = bold ?
*/
if (n == 12) {
if (zero1) {
fprintf(stderr, "%u: only understand 0 x x\n"
"\"%s\"\n", lib->lineno, line);
exit(1);
}
obj->u.text.style = decode_style(style);
obj->type = lib_obj_text;
return 1;
}
if (sscanf(line, "X %ms %ms %d %d %d %c %d %d %u %u %c",
&obj->u.pin.name, &obj->u.pin.number,
&obj->u.pin.x, &obj->u.pin.y, &obj->u.pin.length,
&obj->u.pin.orient,
&obj->u.pin.number_size, &obj->u.pin.name_size,
&obj->unit, &obj->convert, &obj->u.pin.etype) == 11) {
obj->type = lib_obj_pin;
return 1;
}
break;
default:
abort();
}
fprintf(stderr, "%u: cannot parse\n\"%s\"\n", lib->lineno, line);
exit(1);
}
void lib_parse(struct lib *lib, const char *file)
{
lib->state = lib_skip;
lib->lineno = 0;
file_read(file, lib_parse_line, lib);
}
void lib_init(struct lib *lib)
{
lib->comps = NULL;
lib->next_comp = &lib->comps;
}

396
eeshow/lib-render.c Normal file
View File

@ -0,0 +1,396 @@
/*
* lib.c - Render component from library
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 "util.h"
#include "misc.h"
#include "style.h"
#include "gfx.h"
#include "text.h"
#include "sch.h"
#include "lib.h"
/* ----- Drawing ----------------------------------------------------------- */
static void draw_poly(const struct lib_poly *poly, const int m[6])
{
int n = poly->points;
int x[n];
int y[n];
int i;
for (i = 0; i != n; i++) {
x[i] = mx(poly->x[i], poly->y[i], m);
y[i] = my(poly->x[i], poly->y[i], m);
}
gfx_poly(n, x, y, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG);
switch (poly->fill) {
case 'N':
break;
case 'F':
gfx_poly(n, x, y, COLOR_NONE, COLOR_COMP_DWG,
LAYER_COMP_DWG_BG);
break;
case 'f':
gfx_poly(n, x, y, COLOR_NONE, COLOR_COMP_DWG_BG,
LAYER_COMP_DWG_BG);
break;
default:
abort();
}
}
static void draw_rect(const struct lib_rect *rect, const int m[6])
{
int sx = mx(rect->sx, rect->sy, m);
int sy = my(rect->sx, rect->sy, m);
int ex = mx(rect->ex, rect->ey, m);
int ey = my(rect->ex, rect->ey, m);
gfx_rect(sx, sy, ex, ey, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG);
switch (rect->fill) {
case 'N':
break;
case 'F':
gfx_rect(sx, sy, ex, ey, COLOR_NONE, COLOR_COMP_DWG,
LAYER_COMP_DWG_BG);
break;
case 'f':
gfx_rect(sx, sy, ex, ey, COLOR_NONE, COLOR_COMP_DWG_BG,
LAYER_COMP_DWG_BG);
break;
default:
abort();
}
}
static void draw_circ(const struct lib_circ *circ, const int m[6])
{
int x = mx(circ->x, circ->y, m);
int y = my(circ->x, circ->y, m);
int r = circ->r;
gfx_circ(x, y, r, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG);
switch (circ->fill) {
case 'N':
break;
case 'F':
gfx_circ(x, y, r, COLOR_NONE, COLOR_COMP_DWG,
LAYER_COMP_DWG_BG);
break;
case 'f':
gfx_circ(x, y, r, COLOR_NONE, COLOR_COMP_DWG_BG,
LAYER_COMP_DWG_BG);
break;
default:
abort();
}
}
static void draw_arc(const struct lib_arc *arc, const int m[6])
{
int a = matrix_to_angle(m);
int x = mx(arc->x, arc->y, m);
int y = my(arc->x, arc->y, m);
int sa = angle_add(arc->start_a, a);
int ea = angle_add(arc->end_a, a);
if (matrix_is_mirrored(m)) {
sa = 180 - sa;
ea = 180 - ea;
while (ea < sa)
ea += 360;
while (ea - sa > 360)
ea -= 360;
if (ea - sa >= 180) {
swap(sa, ea);
sa += 360;
}
}
gfx_arc(x, y, arc->r, sa, ea,
COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG);
assert(arc->fill == 'N');
}
static void draw_pin_name(const struct comp *comp, const struct lib_pin *pin,
const int m[6], int dx, int dy, int rot, enum text_align hor)
{
int ox, oy, sx, sy;
if (comp->name_offset) {
ox = dx * (pin->length + comp->name_offset);
oy = dy * (pin->length + comp->name_offset);
sx = sy = 0;
} else {
ox = dx * pin->length / 2;
oy = dy * pin->length / 2;
sx = mxr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m);
sy = myr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m);
if (sx > 0)
sx = -sx;
if (sy > 0)
sy = -sy;
}
struct text txt = {
.s = pin->name,
.x = mx(pin->x + ox, pin->y + oy, m) + sx,
.y = my(pin->x + ox, pin->y + oy, m) + sy,
.size = pin->name_size,
.rot = rot,
.hor = comp->name_offset ? hor : text_mid,
.vert = comp->name_offset ? text_mid : text_min,
};
text_rot(&txt, matrix_to_angle(m));
if (matrix_is_mirrored(m)) {
if ((txt.rot % 180) == 0)
txt.hor = text_flip(txt.hor);
else
txt.vert = text_flip(txt.vert);
}
switch (txt.rot) {
case 180:
case 270:
text_flip_x(&txt);
break;
default:
break;
}
text_fig(&txt, COLOR_PIN_NAME, LAYER_PIN_NAME);
}
static void draw_pin_num(const struct comp *comp, const struct lib_pin *pin,
const int m[6], int dx, int dy, int rot, enum text_align hor)
{
int ox, oy, sx, sy;
ox = dx * pin->length / 2;
oy = dy * pin->length / 2;
sx = mxr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m);
sy = myr(-dy * PIN_NUM_OFFSET, dx * PIN_NUM_OFFSET, m);
if (sx > 0)
sx = -sx;
if (sy > 0)
sy = -sy;
if (!comp->name_offset) {
sx = -sx;
sy = -sy;
}
struct text txt = {
.s = pin->number,
.x = mx(pin->x + ox, pin->y + oy, m) + sx,
.y = my(pin->x + ox, pin->y + oy, m) + sy,
.size = pin->number_size,
.rot = rot,
.hor = text_mid,
.vert = comp->name_offset ? text_min : text_max,
};
text_rot(&txt, matrix_to_angle(m) % 180);
if (matrix_is_mirrored(m)) {
switch (txt.rot) {
case 0:
txt.hor = text_flip(txt.hor);
break;
case 90:
break;
case 180:
txt.hor = text_flip(txt.hor);
break;
case 270:
break;
}
}
switch (txt.rot) {
case 180:
case 270:
text_flip_x(&txt);
break;
default:
break;
}
text_fig(&txt, COLOR_PIN_NUMBER, LAYER_PIN_NUMBER);
}
static void draw_pin(const struct comp *comp, const struct lib_pin *pin,
const int m[6])
{
int x[2], y[2];
int dx = 0, dy = 0;
int rot;
enum text_align hor;
switch (pin->orient) {
case 'U':
dy = 1;
rot = 90;
hor = text_min;
break;
case 'D':
dy = -1;
rot = 90;
hor = text_max;
break;
case 'R':
dx = 1;
rot = 0;
hor = text_min;
break;
case 'L':
dx = -1;
rot = 0;
hor = text_max;
break;
default:
abort();
}
x[0] = mx(pin->x, pin->y, m);
y[0] = my(pin->x, pin->y, m);
x[1] = mx(pin->x + dx * pin->length, pin->y + dy * pin->length, m);
y[1] = my(pin->x + dx * pin->length, pin->y + dy * pin->length, m);
gfx_poly(2, x, y, COLOR_COMP_DWG, COLOR_NONE, LAYER_COMP_DWG);
if (comp->show_pin_name)
draw_pin_name(comp, pin, m, dx, dy, rot, hor);
if (comp->show_pin_num)
draw_pin_num(comp, pin, m, dx, dy, rot, hor);
}
static void draw_text(const struct lib_text *text, const int m[6])
{
struct text txt = {
.s = text->s,
.size = text->dim,
.x = mx(text->x, text->y, m),
.y = my(text->x, text->y, m),
.rot = angle_add(text->orient / 10, matrix_to_angle(m)),
};
decode_alignment(&txt, text->hor_align, text->vert_align);
switch (txt.rot) {
case 180:
case 270:
/* @@@ consolidate this with text_flip_x */
txt.rot = angle_add(txt.rot, 180);
txt.hor = text_flip(txt.hor);
txt.vert = text_flip(txt.vert);
// text_flip_x(&txt);
break;
default:
break;
}
if (matrix_is_mirrored(m))
switch (txt.rot) {
case 0:
case 180:
txt.hor = text_flip(txt.hor);
break;
case 90:
case 270:
txt.vert = text_flip(txt.vert);
break;
default:
abort();
}
text_fig(&txt, COLOR_COMP_DWG, WIDTH_COMP_DWG);
}
static void draw(const struct comp *comp, const struct lib_obj *obj,
const int m[6])
{
switch (obj->type) {
case lib_obj_poly:
draw_poly(&obj->u.poly, m);
break;
case lib_obj_rect:
draw_rect(&obj->u.rect, m);
break;
case lib_obj_circ:
draw_circ(&obj->u.circ, m);
break;
case lib_obj_arc:
draw_arc(&obj->u.arc, m);
break;
case lib_obj_text:
draw_text(&obj->u.text, m);
break;
case lib_obj_pin:
draw_pin(comp, &obj->u.pin, m);
break;
default:
abort();
}
}
const struct comp *lib_find(const struct lib *lib, const char *name)
{
const struct comp *comp;
for (comp = lib->comps; comp; comp = comp->next)
if (!strcmp(comp->name, name))
return comp;
fprintf(stderr, "\"%s\" not found\n", name);
exit(1);
}
bool lib_field_visible(const struct comp *comp, int n)
{
return (comp->visible >> n) & 1;
}
void lib_render(const struct comp *comp, unsigned unit, const int m[4])
{
const struct lib_obj *obj;
if (!unit)
unit = 1;
for (obj = comp->objs; obj; obj = obj->next) {
if (obj->unit && obj->unit != unit)
continue;
draw(comp, obj, m);
}
}

124
eeshow/lib.h Normal file
View File

@ -0,0 +1,124 @@
/*
* lib.h - Parse Eeschema .lib file
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 LIB_H
#define LIB_H
#include <stdbool.h>
enum lib_state {
lib_skip, /* before a definition */
lib_def, /* in definition */
lib_draw, /* in drawings */
};
struct lib_obj {
enum lib_obj_type {
lib_obj_poly,
lib_obj_rect,
lib_obj_circ,
lib_obj_arc,
lib_obj_text,
lib_obj_pin,
} type;
unsigned unit;
unsigned convert;
union {
struct lib_poly {
int thick;
char fill;
int points;
int *x;
int *y;
} poly;
struct lib_rect {
int thick;
char fill;
int sx, sy;
int ex, ey;
} rect;
struct lib_circ {
int x, y;
int r;
int thick;
char fill;
} circ;
struct lib_arc {
int x, y;
int r;
int start_a, end_a;
int thick;
char fill;
} arc;
struct lib_text {
int orient;
int x, y;
int dim;
char *s;
enum text_style style;
char hor_align;
char vert_align;
} text;
struct lib_pin {
char *name;
char *number;
int x, y;
int length;
char orient;
int number_size;
int name_size;
char etype;
// @@@ shape
} pin;
} u;
struct lib_obj *next;
};
struct comp {
const char *name;
unsigned units;
unsigned visible; /* visible fields, bit mask */
bool show_pin_name;
bool show_pin_num;
unsigned name_offset;
struct lib_obj *objs;
struct comp *next;
};
struct lib {
enum lib_state state;
unsigned lineno;
struct comp *comps;
struct comp *curr_comp; /* current component */
struct comp **next_comp;
struct lib_obj **next_obj;
};
extern struct comp *comps;
const struct comp *lib_find(const struct lib *lib, const char *name);
bool lib_field_visible(const struct comp *comp, int n);
void lib_render(const struct comp *comp, unsigned unit, const int m[6]);
void lib_parse(struct lib *lib, const char *file);
void lib_init(struct lib *lib);
#endif /* !LIB_H */

172
eeshow/main.c Normal file
View File

@ -0,0 +1,172 @@
/*
* main.c - Convert Eeschema schematics to FIG
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "util.h"
#include "fig.h"
#include "cro.h"
#include "diff.h"
#include "gfx.h"
#include "file.h"
#include "lib.h"
#include "sch.h"
#include "main.h"
int verbose = 0;
static struct gfx_ops const *ops_list[] = {
&fig_ops,
&cro_png_ops,
&cro_pdf_ops,
&diff_ops,
};
void usage(const char *name)
{
fprintf(stderr,
"usage: %s [-r] [-v ...] [[rev:]file.lib ...] [rev:]file.sch\n"
" %*s-- driver_spec\n"
" %s [-v ...] -C [rev:]file\n"
"\n"
" rev git revision\n"
" -r recurse into sub-sheets\n"
" -v increase verbosity of diagnostic output\n"
" -C 'cat' the file to standard output\n"
"\n"
"FIG driver spec:\n"
" fig [-t template.fig] [var=value ...]\n"
"\n"
" var=value substitute \"<var>\" with \"value\" in template\n"
" -t template.fig merge this file with generated output\n"
"\n"
"Cairo PNG driver spec:\n"
" png [-o output.png] [-s scale]\n"
"\n"
" -o output.png generate PNG output and write to specified file\n"
" -s scale scale by indicated factor (default: 1.0)\n"
"\n"
"Cairo PDF driver spec:\n"
" pdf [-o output.pdf] [-s scale]\n"
"\n"
" see PNG\n"
"\n"
"Diff driver spec:\n"
" diff [-o output.pdf] [-s scale] [file.lib ...] file.sch\n"
"\n"
" see PNG\n"
, name, (int) strlen(name) + 1, "", name);
exit(1);
}
int main(int argc, char *const *argv)
{
struct lib lib;
struct sch_ctx sch_ctx;
bool recurse = 0;
const char *cat = NULL;
char c;
int arg, dashdash;
int gfx_argc;
char **gfx_argv;
const struct gfx_ops **ops = ops_list;
for (dashdash = 1; dashdash != argc; dashdash++)
if (!strcmp(argv[dashdash], "--"))
break;
while ((c = getopt(dashdash, argv, "rvC:")) != EOF)
switch (c) {
case 'r':
recurse = 1;
break;
case 'v':
verbose++;
break;
case 'C':
cat = optarg;
break;
default:
usage(*argv);
}
if (cat) {
if (argc != optind)
usage(*argv);
file_read(cat, file_cat, NULL);
return 0;
}
if (dashdash - optind < 1)
usage(*argv);
lib_init(&lib);
for (arg = optind; arg != dashdash - 1; arg++)
lib_parse(&lib, argv[arg]);
if (dashdash == argc) {
gfx_argc = 1;
gfx_argv = alloc_size(sizeof(const char *) * 2);
gfx_argv[0] = (char *) (*ops)->name;
gfx_argv[1] = NULL;
} else {
gfx_argc = argc - dashdash - 1;
if (!gfx_argc)
usage(*argv);
gfx_argv = alloc_size(sizeof(const char *) * (gfx_argc + 1));
memcpy(gfx_argv, argv + dashdash + 1,
sizeof(const char *) * (gfx_argc + 1));
for (ops = ops_list; ops != ARRAY_END(ops_list); ops++)
if (!strcmp((*ops)->name, *gfx_argv))
goto found;
fprintf(stderr, "graphics backend \"%s\" not found\n",
*gfx_argv);
exit(1);
found:
;
}
optind = 0; /* reset getopt */
sch_init(&sch_ctx, recurse);
sch_parse(&sch_ctx, argv[dashdash - 1], &lib);
gfx_init(*ops, gfx_argc, gfx_argv);
if (recurse) {
const struct sheet *sheet;
if (!gfx_multi_sheet()) {
fprintf(stderr,
"graphics backend only supports single sheet\n");
exit(1);
}
for (sheet = sch_ctx.sheets; sheet; sheet = sheet->next) {
sch_render(sheet);
if (sheet->next)
gfx_new_sheet();
}
} else {
sch_render(sch_ctx.sheets);
}
gfx_end();
return 0;
}

31
eeshow/main.h Normal file
View File

@ -0,0 +1,31 @@
/*
* main.h - Convert Eeschema schematics to FIG
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 MAIN_H
#define MAIN_H
#include <stdbool.h>
/*
* 0: no progress indications
* 1: reasonable progress indications
* 2: verbose output
* > 2: go wild !
*/
extern int verbose;
void usage(const char *name);
#endif /* !MAIN_H */

114
eeshow/misc.c Normal file
View File

@ -0,0 +1,114 @@
/*
* misc.c - Helper functions for geometry and attributes
*
* Written 2016 by Werner Almesberger
* Copyright 2016 Werner Almesberger
*
* 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 <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "misc.h"
static bool eq(const int m[6], int xx, int xy, int yx, int yy)
{
return m[1] == xx && m[2] == xy && m[4] == yx && m[5] == yy;
}
unsigned matrix_to_angle(const int m[6])
{
if (eq(m, 1, 0, 0, -1))
return 0;
if (eq(m, 0, -1, -1, 0))
return 90;
if (eq(m, -1, 0, 0, 1))
return 180;
if (eq(m, 0, 1, 1, 0))
return 270;
if (eq(m, -1, 0, 0, -1))
return 0;
if (eq(m, 1, 0, 0, 1)) /* x-flipped */
return 180;
if (eq(m, 0, 1, -1, 0)) /* x-flipped, 90 deg */
return 90;
fprintf(stderr, "unrecognized matrix %d %d %d %d\n",
m[1], m[2], m[4], m[5]);
exit(1);
}
bool matrix_is_mirrored(const int m[6])
{
if (eq(m, 1, 0, 0, -1))
return 0;
if (eq(m, 0, -1, -1, 0))
return 0;
if (eq(m, -1, 0, 0, 1))
return 0;
if (eq(m, 0, 1, 1, 0))
return 0;
if (eq(m, -1, 0, 0, -1))
return 1;
if (eq(m, 1, 0, 0, 1))
return 1;
if (eq(m, 0, 1, -1, 0))
return 1;
assert(0);
}
int angle_add(int a, int b)
{
a += b;
while (a < 0)
a += 360;
return a % 360;
}
int rx(int x, int y, int rot)
{
switch (rot) {
case 0:
return x;
case 90:
return y;
case 180:
return -x;
case 270:
return -y;
default:
assert(0);
}
}
int ry(int x, int y, int rot)
{
switch (rot) {
case 0:
return y;
case 90:
return -x;
case 180:
return -y;
case 270:
return x;
default:
assert(0);
}
}

51
eeshow/misc.h Normal file
View File

@ -0,0 +1,51 @@
/*
* misc.h - Helper functions for geometry and attributes
*
* Written 2016 by Werner Almesberger
* Copyright 2016 Werner Almesberger
*
* 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 MISC_H
#define MISC_H
#include <stdbool.h>
static inline int mxr(int x, int y, const int m[6])
{
return x * m[1] + y * m[2];
}
static inline int myr(int x, int y, const int m[6])
{
return x * m[4] + y * m[5];
}
static inline int mx(int x, int y, const int m[6])
{
return m[0] + mxr(x, y, m);
}
static inline int my(int x, int y, const int m[6])
{
return m[3] + myr(x, y, m);
}
unsigned matrix_to_angle(const int m[6]);
bool matrix_is_mirrored(const int m[6]);
int angle_add(int a, int b);
int rx(int x, int y, int rot);
int ry(int x, int y, int rot);
#endif /* !MISC_H */

View File

@ -0,0 +1,15 @@
#FIG 3.2 Produced by xfig version 3.2.5c
Landscape
Center
Metric
A4
100.00
Single
-2
1200 2
0 32 #c0c0c0
2 2 0 1 7 7 250 -1 -1 0.000 0 0 -1 0 0 5
225 450 19350 450 19350 13500 225 13500 225 450
4 2 32 199 -1 18 150 0.0000 4 1890 13980 19305 13455 <NUMBER>\001
4 2 0 50 -1 18 24 0.0000 4 300 1635 19125 13140 <TITLE>\001
4 0 0 250 -1 22 12 0.0000 4 180 3090 315 13410 CC-BY-SA (c) 2014-2016 Neo900 & GDC\001

342
eeshow/record.c Normal file
View File

@ -0,0 +1,342 @@
/*
* record.c - Record graphics operations by layers and replay
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <limits.h>
#include <math.h>
#include "util.h"
#include "style.h"
#include "gfx.h"
#include "text.h"
#include "record.h"
struct record_obj {
enum ro_type {
ro_line,
ro_rect,
ro_poly,
ro_circ,
ro_arc,
ro_text,
} type;
int x, y;
int color, fill_color;
union {
struct {
int ex, ey;
} line;
struct {
int ex, ey;
} rect;
struct {
unsigned n;
int *vx, *vy;
} poly;
struct {
int r;
} circ;
struct {
int r;
int sa, ea;
} arc;
struct {
char *s;
unsigned size;
enum text_align align;
int rot;
} text;
} u;
struct record_obj *next;
};
static void bb(struct record *rec, int x, int y)
{
if (rec->xmin > x)
rec->xmin = x;
if (rec->ymin > y)
rec->ymin = y;
if (rec->xmax < x)
rec->xmax = x;
if (rec->ymax < y)
rec->ymax = y;
}
static void bb_rot(struct record *rec, int x, int y, int rot)
{
double a = -rot / 180.0 * M_PI;
// @@@ figure this out later
return;
bb(rec, cos(a) * x + sin(a) * y, cos(a) * y - sin(a) * x);
}
static struct record_obj *new_obj(struct record *rec, enum ro_type type,
int color, int fill_color, unsigned layer)
{
struct record_layer **curr_layer;
struct record_layer *new_layer;
struct record_obj *new_obj;
for (curr_layer = &rec->layers; *curr_layer;
curr_layer= &(*curr_layer)->next) {
if ((*curr_layer)->layer == layer)
goto this_layer;
if ((*curr_layer)->layer < layer)
break;
}
new_layer = alloc_type(struct record_layer);
new_layer->layer = layer;
new_layer->objs = NULL;
new_layer->next_obj = &new_layer->objs;
new_layer->next = *curr_layer;
*curr_layer = new_layer;
this_layer:
new_obj = alloc_type(struct record_obj);
new_obj->type = type;
new_obj->color = color;
new_obj->fill_color = fill_color;
new_obj->next = NULL;
*(*curr_layer)->next_obj = new_obj;
(*curr_layer)->next_obj = &new_obj->next;
return new_obj;
}
void record_line(void *ctx, int sx, int sy, int ex, int ey,
int color, unsigned layer)
{
struct record *rec = ctx;
struct record_obj *obj =
new_obj(rec, ro_line, color, COLOR_NONE, layer);
bb(rec, sx, sy);
bb(rec, ex, ey);
obj->x = sx;
obj->y = sy;
obj->u.line.ex = ex;
obj->u.line.ey = ey;
}
void record_rect(void *ctx, int sx, int sy, int ex, int ey,
int color, int fill_color, unsigned layer)
{
struct record *rec = ctx;
struct record_obj *obj =
new_obj(rec, ro_rect, color, fill_color, layer);
bb(rec, sx, sy);
bb(rec, ex, ey);
obj->x = sx;
obj->y = sy;
obj->u.rect.ex = ex;
obj->u.rect.ey = ey;
}
void record_poly(void *ctx,
int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer)
{
struct record *rec = ctx;
struct record_obj *obj =
new_obj(ctx, ro_poly, color, fill_color, layer);
int i;
unsigned size;
for (i = 0; i != points; i++)
bb(rec, x[i], y[i]);
obj->u.poly.n = points;
size = sizeof(int) * points;
obj->u.poly.vx = alloc_size(size);
obj->u.poly.vy = alloc_size(size);
memcpy(obj->u.poly.vx, x, size);
memcpy(obj->u.poly.vy, y, size);
}
void record_circ(void *ctx, int x, int y, int r,
int color, int fill_color, unsigned layer)
{
struct record *rec = ctx;
struct record_obj *obj =
new_obj(ctx, ro_circ, color, fill_color, layer);
bb(rec, x - r, y - r);
bb(rec, x + r, y + r);
obj->x = x;
obj->y = y;
obj->u.circ.r = r;
}
void record_arc(void *ctx, int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer)
{
struct record *rec = ctx;
struct record_obj *obj = new_obj(ctx, ro_arc, color, fill_color, layer);
bb(rec, x - r, y - r);
bb(rec, x + r, y + r);
obj->x = x;
obj->y = y;
obj->u.arc.r = r;
obj->u.arc.sa = sa;
obj->u.arc.ea = ea;
}
void record_text(void *ctx, int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer)
{
struct record *rec = ctx;
struct record_obj *obj =
new_obj(ctx, ro_text, color, COLOR_NONE, layer);
unsigned width = rec->ops->text_width(rec->user, s, size);
bb_rot(rec, x, y - size, rot);
bb_rot(rec, x + width, y, rot);
obj->x = x;
obj->y = y;
obj->u.text.s = stralloc(s);
obj->u.text.size = size;
obj->u.text.align = align;
obj->u.text.rot = rot;
}
void record_init(struct record *rec, const struct gfx_ops *ops, void *user)
{
rec->ops = ops;
rec->user = user;
rec->xmin = rec->ymin = INT_MAX;
rec->xmax = rec->ymax = INT_MIN;
rec->layers = NULL;
}
void record_wipe(struct record *rec)
{
rec->layers = NULL;
}
void record_replay(const struct record *rec)
{
const struct gfx_ops *ops = rec->ops;
void *ctx = rec->user;
const struct record_layer *layer;
const struct record_obj *obj;
for (layer = rec->layers; layer; layer = layer->next)
for (obj = layer->objs; obj; obj = obj->next)
switch (obj->type) {
case ro_line:
ops->line(ctx, obj->x, obj->y,
obj->u.line.ex, obj->u.line.ey,
obj->color, layer->layer);
break;
case ro_rect:
ops->rect(ctx, obj->x, obj->y,
obj->u.rect.ex, obj->u.rect.ey,
obj->color, obj->fill_color, layer->layer);
break;
case ro_poly:
ops->poly(ctx, obj->u.poly.n,
obj->u.poly.vx, obj->u.poly.vy,
obj->color, obj->fill_color, layer->layer);
break;
case ro_circ:
ops->circ(ctx, obj->x, obj->y,
obj->u.circ.r,
obj->color, obj->fill_color, layer->layer);
break;
case ro_arc:
ops->arc(ctx, obj->x, obj->y, obj->u.arc.r,
obj->u.arc.sa, obj->u.arc.ea,
obj->color, obj->fill_color, layer->layer);
break;
case ro_text:
ops->text(ctx, obj->x, obj->y, obj->u.text.s,
obj->u.text.size, obj->u.text.align,
obj->u.text.rot,
obj->color, layer->layer);
break;
default:
abort();
}
}
void record_bbox(const struct record *rec, int *x, int *y, int *w, int *h)
{
if (x)
*x = rec->xmin;
if (y)
*y = rec->ymin;
if (w)
*w = rec->xmax - rec->xmin + 1;
if (h)
*h = rec->ymax - rec->ymin + 1;
}
static void record_obj_destroy(struct record_obj *obj)
{
switch (obj->type) {
case ro_poly:
free(obj->u.poly.vx);
free(obj->u.poly.vy);
break;
case ro_text:
free(obj->u.text.s);
break;
default:
break;
}
free(obj);
}
void record_destroy(struct record *rec)
{
struct record_layer *next_layer;
struct record_obj *next_obj;
while (rec->layers) {
next_layer = rec->layers->next;
while (rec->layers->objs) {
next_obj = rec->layers->objs->next;
record_obj_destroy(rec->layers->objs);
rec->layers->objs = next_obj;
}
free(rec->layers);
rec->layers = next_layer;
}
}

58
eeshow/record.h Normal file
View File

@ -0,0 +1,58 @@
/*
* record.h - Record graphics operations by layers and replay
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 RECORD_H
#define RECORD_H
#include "gfx.h"
struct record_obj;
struct record_layer {
unsigned layer;
struct record_obj *objs;
struct record_obj **next_obj;
struct record_layer *next;
};
struct record {
const struct gfx_ops *ops;
void *user;
int xmin, xmax;
int ymin, ymax;
struct record_layer *layers;
};
void record_line(void *ctx, int sx, int sy, int ex, int ey,
int color, unsigned layer);
void record_rect(void *ctx, int sx, int sy, int ex, int ey,
int color, int fill_color, unsigned layer);
void record_poly(void *ctx,
int points, const int x[points], const int y[points],
int color, int fill_color, unsigned layer);
void record_circ(void *ctx, int x, int y, int r,
int color, int fill_color, unsigned layer);
void record_arc(void *ctx, int x, int y, int r, int sa, int ea,
int color, int fill_color, unsigned layer);
void record_text(void *ctx, int x, int y, const char *s, unsigned size,
enum text_align align, int rot, unsigned color, unsigned layer);
void record_init(struct record *rec, const struct gfx_ops *ops, void *user);
void record_wipe(struct record *rec);
void record_replay(const struct record *rec);
void record_bbox(const struct record *rec, int *x, int *y, int *w, int *h);
void record_destroy(struct record *rec);
#endif /* !RECORD_H */

562
eeshow/sch-parse.c Normal file
View File

@ -0,0 +1,562 @@
/*
* sch-parse.c - Parse Eeschema .sch file
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include "util.h"
#include "dwg.h"
#include "file.h"
#include "lib.h"
#include "sch.h"
/* ----- (Global) Labels --------------------------------------------------- */
static enum dwg_shape do_decode_shape(const char *s)
{
if (!strcmp(s, "UnSpc"))
return dwg_unspec;
if (!strcmp(s, "Input"))
return dwg_in;
if (!strcmp(s, "Output"))
return dwg_out;
if (!strcmp(s, "3State"))
return dwg_tri;
if (!strcmp(s, "BiDi"))
return dwg_bidir;
fprintf(stderr, "unknown shape: \"%s\"\n", s);
exit(1);
}
static enum dwg_shape decode_shape(const char *s)
{
enum dwg_shape res;
res = do_decode_shape(s);
free((void *) s);
return res;
}
/* ----- Component fields -------------------------------------------------- */
void decode_alignment(struct text *txt, char hor, char vert)
{
switch (hor) {
case 'L':
txt->hor = text_min;
break;
case 'C':
txt->hor = text_mid;
break;
case 'R':
txt->hor = text_max;
break;
default:
assert(0);
}
switch (vert) {
case 'B':
txt->vert = text_min;
break;
case 'C':
txt->vert = text_mid;
break;
case 'T':
txt->vert = text_max;
break;
default:
assert(0);
}
}
static bool parse_field(struct sch_ctx *ctx, const char *line)
{
struct sch_comp *comp = &ctx->obj.u.comp;
int n;
unsigned flags;
char hv, hor, vert, italic, bold;
struct comp_field *field;
struct text *txt;
field = alloc_type(struct comp_field);
txt = &field->txt;
if (sscanf(line, "F %d \"\" %c %d %d %u %u %c %c%c%c",
&n, &hv, &txt->x, &txt->y, &txt->size, &flags, &hor, &vert,
&italic, &bold) == 10) {
free(field);
return 1;
}
if (sscanf(line, "F %d \"%m[^\"]\" %c %d %d %u %u %c %c%c%c",
&n, &txt->s, &hv, &txt->x, &txt->y, &txt->size, &flags,
&hor, &vert, &italic, &bold) != 11)
return 0;
if (flags || !lib_field_visible(comp->comp, n)) {
free(field);
return 1;
}
if (n == 0 && comp->comp->units > 1) {
int len = strlen(txt->s);
char *s;
s = realloc((void *) txt->s, len + 3);
if (!s) {
perror("realloc");
exit(1);
}
if (comp->unit <= 26)
sprintf(s + len, "%c", 'A' + comp->unit - 1);
else
sprintf(s + len, "%c%c",
'A' + (comp->unit - 1) / 26 - 1,
'A' + (comp->unit - 1) % 26);
txt->s = s;
}
field->next = comp->fields;
comp->fields = field;
switch (hv) {
case 'H':
txt->rot = 0;
break;
case 'V':
txt->rot = 90;
break;
default:
assert(0);
}
decode_alignment(txt, hor, vert);
// @@@ decode font
return 1;
}
/* ----- Sheet field ------------------------------------------------------- */
static enum dwg_shape decode_form(char form)
{
switch (form) {
case 'O':
return dwg_in;
case 'I':
return dwg_out;
case 'B':
/* fall through */
case 'T':
return dwg_bidir;
case 'U':
return dwg_unspec;
default:
fprintf(stderr, "unknown form: \"%c\"\n", form);
exit(1);
}
}
static int decode_side(char side)
{
switch (side) {
case 'L':
return 2; /* left */
case 'B':
return 1; /* up */
case 'R':
return 0; /* right */
case 'T':
return 3; /* down */
default:
fprintf(stderr, "unknown side: \"%c\"\n", side);
exit(1);
}
}
static bool parse_hsheet_field(struct sch_ctx *ctx, const char *line)
{
struct sch_sheet *sheet = &ctx->obj.u.sheet;
char *s;
char form, side;
unsigned n, dim;
struct sheet_field *field;
if (sscanf(line, "F%d \"%m[^\"]\" %u", &n, &s, &dim) == 3) {
switch (n) {
case 0:
sheet->sheet = s;
sheet->sheet_dim = dim;
return 1;
case 1:
sheet->file = s;
sheet->file_dim = dim;
return 1;
default:
assert(0);
}
}
field = alloc_type(struct sheet_field);
if (sscanf(line, "F%d \"%m[^\"]\" %c %c %d %d %u",
&n, &field->s, &form, &side, &field->x, &field->y, &field->dim)
!= 7) {
free(field);
return 0;
}
assert(n >= 2);
if (side == 'B' || side == 'T') {
/*
* This is beautiful: since there is no indication for rotation
* on the hsheet, or the sheet or file fields, we need to look
* at whether the imported sheet pins go left or right (no
* rotation) or whether they go top or bottom (rotation).
*
* A sheet with no imported pins lacks these hints, and is
* therefore always assumed to be without rotation.
*
* Eeschema is careful to be consistent, and does not allow
* sheets with no imported pins to be rotated. Even better, it
* flips rotated sheets where the last imported pin is deleted
* back.
*/
sheet->rotated = 1;
}
field->shape = decode_form(form);
field->side = decode_side(side);
field->next = sheet->fields;
sheet->fields = field;
return 1;
}
/* ----- Schematics parser ------------------------------------------------- */
static void submit_obj(struct sch_ctx *ctx, enum sch_obj_type type)
{
struct sch_obj *obj;
obj = alloc_type(struct sch_obj);
*obj = ctx->obj;
obj->type = type;
obj->next = NULL;
*ctx->next_obj = obj;
ctx->next_obj = &obj->next;
}
static struct sheet *new_sheet(struct sch_ctx *ctx)
{
struct sheet *sheet;
sheet = alloc_type(struct sheet);
sheet->objs = NULL;
sheet->next = NULL;
ctx->next_obj = &sheet->objs;
*ctx->next_sheet = sheet;
ctx->next_sheet = &sheet->next;
return sheet;
}
static bool parse_line(void *user, const char *line);
static void recurse_sheet(struct sch_ctx *ctx)
{
struct sch_obj **saved_next_obj = ctx->next_obj;
const char *parent = ctx->file->name;
char *tmp = NULL;
struct sch_file dsc = {
.name = ctx->obj.u.sheet.file,
.lineno = 0,
.parent = ctx->file,
};
/* @@@ clean this up */
if (access(dsc.name, R_OK)) {
const char *slash;
slash = strrchr(parent, '/');
if (slash) {
unsigned len = slash + 1 - parent;
tmp = alloc_size(len + strlen(dsc.name) + 1);
memcpy(tmp, parent, len);
strcpy(tmp + len, dsc.name);
dsc.name = tmp;
}
}
new_sheet(ctx);
ctx->file = &dsc;
ctx->state = sch_descr;
file_read(dsc.name, parse_line, ctx);
ctx->file = dsc.parent;
ctx->next_obj = saved_next_obj;
free(tmp);
}
static bool parse_line(void *user, const char *line)
{
struct sch_ctx *ctx = user;
struct sch_obj *obj = &ctx->obj;
int n = 0;
char *s;
ctx->file->lineno++;
switch (ctx->state) {
case sch_basic:
if (sscanf(line, "$Comp%n", &n) == 0 && n) {
ctx->state = sch_comp;
obj->u.comp.fields = NULL;
return 1;
}
if (sscanf(line, "$Sheet%n", &n) == 0 && n) {
ctx->state = sch_sheet;
obj->u.sheet.sheet = NULL;
obj->u.sheet.file = NULL;
obj->u.sheet.rotated = 0;
obj->u.sheet.fields = NULL;
return 1;
}
/* Text */
struct sch_text *text = &obj->u.text;
if (sscanf(line, "Text Notes %d %d %d %d",
&obj->x, &obj->y, &text->dir, &text->dim) == 4) {
ctx->state = sch_text;
obj->u.text.fn = dwg_text;
return 1;
}
if (sscanf(line, "Text GLabel %d %d %d %d %ms",
&obj->x, &obj->y, &text->dir, &text->dim, &s) == 5) {
ctx->state = sch_text;
obj->u.text.fn = dwg_glabel;
obj->u.text.shape = decode_shape(s);
return 1;
}
if (sscanf(line, "Text HLabel %d %d %d %d %ms",
&obj->x, &obj->y, &text->dir, &text->dim, &s) == 5) {
ctx->state = sch_text;
obj->u.text.fn = dwg_hlabel;
obj->u.text.shape = decode_shape(s);
return 1;
}
if (sscanf(line, "Text Label %d %d %d %d",
&obj->x, &obj->y, &text->dir, &text->dim) == 4) {
ctx->state = sch_text;
obj->u.text.fn = dwg_label;
return 1;
}
/* Connection */
if (sscanf(line, "Connection ~ %d %d", &obj->x, &obj->y) == 2) {
submit_obj(ctx, sch_obj_junction);
return 1;
}
/* NoConn */
if (sscanf(line, "NoConn ~ %d %d", &obj->x, &obj->y) == 2) {
submit_obj(ctx, sch_obj_noconn);
return 1;
}
/* Wire */
if (sscanf(line, "Wire Wire Line%n", &n) == 0 && n) {
ctx->state = sch_wire;
obj->u.wire.fn = dwg_wire;
return 1;
}
if (sscanf(line, "Wire Bus Line%n", &n) == 0 && n) {
ctx->state = sch_wire;
obj->u.wire.fn = dwg_bus;
return 1;
}
if (sscanf(line, "Wire Notes Line%n", &n) == 0 && n) {
ctx->state = sch_wire;
obj->u.wire.fn = dwg_line;
return 1;
}
/* Entry */
/*
* Documentation mentions the following additional variants:
*
* - Entry Wire Line equivalent:
* Wire Wire Bus
* Entry Wire Bus
*
* - Entry Bus Bus equivalent:
* Wire Bus Bus
*/
if (sscanf(line, "Entry Wire Line%n", &n) == 0 && n) {
ctx->state = sch_wire;
obj->u.wire.fn = dwg_wire;
return 1;
}
if (sscanf(line, "Entry Bus Bus%n", &n) == 0 && n) {
ctx->state = sch_wire;
obj->u.wire.fn = dwg_bus;
return 1;
}
/* EndSCHEMATC */
if (sscanf(line, "$EndSCHEMATC%n", &n) == 0 && n)
return 0;
break;
case sch_descr:
if (sscanf(line, "$EndDescr%n", &n) || !n)
return 1;
ctx->state = sch_basic;
return 1;
case sch_comp:
if (sscanf(line, "$EndComp%n", &n) == 0 && n) {
ctx->state = sch_basic;
submit_obj(ctx, sch_obj_comp);
return 1;
}
if (sscanf(line, "L %ms", &s) == 1) {
obj->u.comp.comp = lib_find(ctx->lib, s);
free(s);
return 1;
}
if (sscanf(line, "U %u", &obj->u.comp.unit) == 1)
return 1;
if (sscanf(line, "P %d %d", &obj->x, &obj->y) == 2)
return 1;
if (parse_field(ctx, line))
return 1;
if (sscanf(line, "AR %n", &n) == 0 && n)
return 1; /* @@@ what is "AR" ? */
n = sscanf(line, " %d %d %d %d",
obj->u.comp.m + 1, obj->u.comp.m + 2,
obj->u.comp.m + 4, obj->u.comp.m + 5);
if (n == 3)
return 1;
if (n == 4) {
obj->u.comp.m[0] = obj->x;
obj->u.comp.m[3] = obj->y;
return 1;
}
break;
case sch_sheet:
if (sscanf(line, "$EndSheet%n", &n) == 0 && n) {
submit_obj(ctx, sch_obj_sheet);
if (ctx->recurse)
recurse_sheet(ctx);
ctx->state = sch_basic;
return 1;
}
if (sscanf(line, "S %d %d %u %u",
&obj->x, &obj->y, &obj->u.sheet.w, &obj->u.sheet.h) == 4)
return 1;
if (sscanf(line, "U %*x%n", &n) == 0 && n)
return 1;
if (parse_hsheet_field(ctx, line))
return 1;
break;
case sch_text:
ctx->state = sch_basic;
{
const char *from;
char *to;
s = alloc_size(strlen(line) + 1);
from = line;
to = s;
while (*from) {
if (from[0] != '\\' || from[1] != 'n') {
*to++ = *from++;
continue;
}
*to++ = '\n';
from += 2;
}
*to = 0;
obj->u.text.s = s;
submit_obj(ctx, sch_obj_text);
}
return 1;
case sch_wire:
if (sscanf(line, "%d %d %d %d", &obj->x, &obj->y,
&obj->u.wire.ex, &obj->u.wire.ey) != 4)
break;
submit_obj(ctx, sch_obj_wire);
ctx->state = sch_basic;
return 1;
default:
abort();
}
fprintf(stderr, "%s:%u: cannot parse\n\"%s\"\n",
ctx->file->name, ctx->file->lineno, line);
exit(1);
}
void sch_parse(struct sch_ctx *ctx, const char *file, const struct lib *lib)
{
struct sch_file dsc = {
.name = file,
.lineno = 0,
.parent = NULL,
};
ctx->file = &dsc;
ctx->lib = lib;
file_read(file, parse_line, ctx);
}
void sch_init(struct sch_ctx *ctx, bool recurse)
{
ctx->state = sch_descr;
ctx->recurse = recurse;
ctx->sheets = NULL;
ctx->next_sheet = &ctx->sheets;
new_sheet(ctx);
}

174
eeshow/sch-render.c Normal file
View File

@ -0,0 +1,174 @@
/*
* sch-render.c - Render schematics
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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.
*/
#define _GNU_SOURCE /* for asprintf */
#include <stdio.h>
#include <assert.h>
#include "misc.h"
#include "style.h"
#include "gfx.h"
#include "dwg.h"
#include "lib.h"
#include "sch.h"
/* ----- Rendering --------------------------------------------------------- */
static void dump_field(const struct comp_field *field, const int m[6])
{
struct text txt = field->txt;
int dx, dy;
dx = txt.x - m[0];
dy = txt.y - m[3];
txt.x = mx(dx, dy, m);
txt.y = my(dx, dy, m);
text_rot(&txt, matrix_to_angle(m));
switch (txt.rot) {
case 180:
text_rot(&txt, 180);
txt.hor = text_flip(txt.hor);
txt.vert = text_flip(txt.vert);
break;
case 270:
text_rot(&txt, 180);
txt.vert = text_flip(txt.vert);
txt.hor = text_flip(txt.hor);
break;
default:
break;
}
if (matrix_is_mirrored(m)) {
if ((txt.rot % 180) == 0)
txt.hor = text_flip(txt.hor);
else
txt.vert = text_flip(txt.vert);
}
text_fig(&txt, COLOR_FIELD, LAYER_FIELD);
}
static void do_hsheet_text(const struct sch_obj *obj,
const struct sch_sheet *sheet)
{
char *s;
assert(sheet->sheet && sheet->file);
struct text sheet_txt = {
.size = sheet->sheet_dim,
.x = obj->x,
.y = obj->y,
.rot = 0,
.hor = text_min,
.vert = text_min,
};
if (asprintf(&s, "Sheet: %s", sheet->sheet)) {}
sheet_txt.s = s; /* work around "const" mismatch */
struct text file_txt = {
.size = sheet->file_dim,
.x = obj->x,
.y = obj->y,
.rot = 0,
.hor = text_min,
.vert = text_max,
};
if (asprintf(&s, "File: %s", sheet->file)) {}
file_txt.s = s; /* work around "const" mismatch */
if (sheet->rotated) {
sheet_txt.rot = file_txt.rot = 90;
sheet_txt.x -= HSHEET_FIELD_OFFSET;
sheet_txt.y += sheet->h;
file_txt.x += sheet->w + HSHEET_FIELD_OFFSET;
file_txt.y += sheet->h;
} else {
sheet_txt.y -= HSHEET_FIELD_OFFSET;
file_txt.y += sheet->h + HSHEET_FIELD_OFFSET;
}
text_fig(&sheet_txt, COLOR_HSHEET_SHEET, LAYER_HSHEET_FIELD);
text_fig(&file_txt, COLOR_HSHEET_FILE, LAYER_HSHEET_FIELD);
// free((void *) ctx->sheet);
// free((void *) ctx->file);
}
static void render_sheet(const struct sch_obj *obj,
const struct sch_sheet *sheet)
{
const struct sheet_field *field;
gfx_rect(obj->x, obj->y, obj->x + sheet->w, obj->y + sheet->h,
COLOR_HSHEET_BOX, COLOR_NONE, LAYER_HSHEET_BOX);
do_hsheet_text(obj, sheet);
for (field = sheet->fields; field; field = field->next)
dwg_hlabel(obj->x, obj->y, field->s,
field->side, field->dim,
field->shape);
// free(field->s)
}
void sch_render(const struct sheet *sheet)
{
const struct sch_obj *obj;
for (obj = sheet->objs; obj; obj = obj->next)
switch (obj->type) {
case sch_obj_wire:
{
const struct sch_wire *wire = &obj->u.wire;
wire->fn(obj->x, obj->y, wire->ex, wire->ey);
}
break;
case sch_obj_junction:
dwg_junction(obj->x, obj->y);
break;
case sch_obj_noconn:
dwg_noconn(obj->x, obj->y);
break;
case sch_obj_text:
{
const struct sch_text *text = &obj->u.text;
text->fn(obj->x, obj->y, text->s, text->dir,
text->dim, text->shape);
}
break;
case sch_obj_comp:
{
const struct sch_comp *comp = &obj->u.comp;
const struct comp_field *field;
lib_render(comp->comp, comp->unit, comp->m);
for (field = comp->fields; field;
field = field->next)
dump_field(field, comp->m);
}
break;
case sch_obj_sheet:
render_sheet(obj, &obj->u.sheet);
break;
}
}

123
eeshow/sch.h Normal file
View File

@ -0,0 +1,123 @@
/*
* sch.h - Parse Eeschema .sch file
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 SCH_H
#define SCH_H
#include <stdbool.h>
#include "dwg.h"
#include "text.h"
#include "lib.h"
enum sch_state {
sch_basic, /* basic state */
sch_descr, /* prelude and description */
sch_comp, /* component */
sch_sheet, /* sub-sheet */
sch_text, /* text or label */
sch_wire, /* wire */
};
struct sch_obj {
enum sch_obj_type {
sch_obj_wire,
sch_obj_junction,
sch_obj_noconn,
sch_obj_text,
sch_obj_comp,
sch_obj_sheet,
} type;
int x, y;
union {
struct sch_wire {
void (*fn)(int sx, int sy, int ex, int ey);
int ex, ey;
} wire;
struct sch_text {
void (*fn)(int x, int y, const char *s,
int dir, int dim, enum dwg_shape shape);
const char *s;
int dir; /* orientation */
int dim; /* dimension */
enum dwg_shape shape;
} text;
struct sch_comp {
const struct comp *comp; /* current component */
unsigned unit; /* unit of current component */
struct comp_field {
struct text txt;
struct comp_field *next;
} *fields;
int m[6];
} comp;
struct sch_sheet {
unsigned h, w;
const char *sheet;
unsigned sheet_dim;
const char *file;
unsigned file_dim;
bool rotated;
struct sheet_field {
char *s;
int x, y;
unsigned dim;
enum dwg_shape shape;
unsigned side;
struct sheet_field *next;
} *fields;
} sheet;
} u;
struct sch_obj *next;
};
struct sheet {
struct sch_obj *objs;
struct sheet *next;
};
struct sch_file {
const char *name;
int lineno;
struct sch_file *parent;
};
struct sch_ctx {
enum sch_state state;
bool recurse;
struct sch_obj obj;
struct sch_obj **next_obj;
struct sheet *sheets;
struct sheet **next_sheet;
const struct lib *lib;
struct sch_file *file;
};
void decode_alignment(struct text *txt, char hor, char vert);
void sch_render(const struct sheet *sheet);
void sch_parse(struct sch_ctx *ctx, const char *file, const struct lib *lib);
void sch_init(struct sch_ctx *ctx, bool recurse);
#endif /* !SCH_H */

92
eeshow/sch2pdf Executable file
View File

@ -0,0 +1,92 @@
#!/bin/bash
#
# sch2pdf - Generate PDF from schematics, using eeshow
#
# Written 2016 by Werner Almesberger
# Copyright 2016 by Werner Almesberger
#
# 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.
#
#
# Known bugs:
# - expects first sheet to be index page
# - only renders sub-sheets
# - has all the limitations of eeshow (see TODO)
#
usage()
{
cat <<EOF 1>&2
usage: $0 [-n first_num] [-o output.pdf] [-q] [-t template.fig ]
file.lib ... file.sch
EOF
exit 1
}
out=out.pdf
quiet=false
template=
num=1
while [ "$1" ]; do
case "$1" in
-n) num=$2
shift 2;;
-o) out=$2
shift 2;;
-q) quiet=true
shift;;
-t) template="-t $2"
shift 2;;
-*) usage;;
*) break;;
esac
done
[ "$1" ] || usage
libs=
while [ "$2" ]; do
libs="$libs $1"
shift
done
./eeshow $libs "$1" \
-- fig $template "TITLE=`basename \"$1\" .sch`" NUMBER=$num |
fig2dev -L pdf >"$out"
sheet=false
while read line; do
if ! $sheet; then
[ "${line#\$Sheet}" != "$line" ] && sheet=true
continue
else
if [ "${line#\$EndSheet}" != "$line" ]; then
sheet=false
continue
fi
fi
if [ "${line#F0 \"}" != "$line" ]; then
name=${line#F0 \"}
name=${name%%\"*}
fi
[ "${line#F1 \"}" = "$line" ] && continue
file=${line#F1 \"}
file=${file%%\"*}
num=`expr $num + 1`
$quiet || echo "$file" 1>&2
./eeshow $libs `dirname "$1"`/$file \
-- fig $template "TITLE=$name" NUMBER=$num |
fig2dev -L pdf >_tmp.pdf
pdfunite "$out" _tmp.pdf _tmp2.pdf
mv _tmp2.pdf "$out"
done <"$1"
exit

31
eeshow/style.c Normal file
View File

@ -0,0 +1,31 @@
/*
* style.c - Drawing style
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stdint.h>
#include "style.h"
uint32_t color_rgb[] = {
[COLOR_BLACK] = 0x000000,
[COLOR_BLUE] = 0x0000ff,
[COLOR_YELLOW] = 0xffff00,
[COLOR_WHITE] = 0xffffff,
[COLOR_GREEN4] = 0x009000,
[COLOR_CYAN4] = 0x009090,
[COLOR_CYAN3] = 0x00b0b0,
[COLOR_RED4] = 0x900000,
[COLOR_RED3] = 0xb00000,
[COLOR_MAGENTA4] = 0x900090,
[COLOR_BROWN2] = 0xc06000,
[COLOR_DARK_YELLOW] = 0x848400,
};

91
eeshow/style.h Normal file
View File

@ -0,0 +1,91 @@
/*
* style.h - Drawing style
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 STYLE_H
#define STYLE_H
#include <stdint.h>
/* FIG colors */
#define COLOR_NONE -1
#define COLOR_BLACK 0
#define COLOR_BLUE 1
#define COLOR_YELLOW 6
#define COLOR_WHITE 7
#define COLOR_GREEN4 12
#define COLOR_CYAN4 15
#define COLOR_CYAN3 16
#define COLOR_RED4 18
#define COLOR_RED3 19
#define COLOR_MAGENTA4 21
#define COLOR_BROWN2 26
#define COLOR_DARK_YELLOW 32 /* user-defined */
#define COLOR_COMP_DWG COLOR_RED4
#define COLOR_COMP_DWG_BG COLOR_YELLOW
#define COLOR_SHEET_DWG COLOR_BLUE
#define COLOR_TEXT COLOR_BLUE
#define COLOR_WIRE COLOR_GREEN4
#define COLOR_BUS COLOR_BLUE
#define COLOR_NOCONN COLOR_BLUE
#define COLOR_GLABEL COLOR_RED4
#define COLOR_HLABEL COLOR_DARK_YELLOW
#define COLOR_HSHEET_BOX COLOR_MAGENTA4
#define COLOR_HSHEET_SHEET COLOR_FIELD
#define COLOR_HSHEET_FILE COLOR_HLABEL
#define COLOR_LABEL COLOR_BLACK
#define COLOR_FIELD COLOR_CYAN4
#define COLOR_PIN_NAME COLOR_FIELD
#define COLOR_PIN_NUMBER COLOR_RED4
#define FONT_HELVETICA_BOLD 18
#define LAYER_GLABEL 20
#define LAYER_HLABEL LAYER_GLABEL
#define LAYER_LABEL LAYER_GLABEL
#define LAYER_TEXT 30
#define LAYER_NOCONN 40
#define LAYER_WIRES 50
#define LAYER_BUSSES LAYER_WIRES
#define LAYER_FIELD 60
#define LAYER_PIN_NAME LAYER_FIELD
#define LAYER_PIN_NUMBER LAYER_FIELD
#define LAYER_HSHEET_FIELD LAYER_FIELD
#define LAYER_HSHEET_BOX 70
#define LAYER_LINES 100
#define LAYER_COMP_DWG 120
#define LAYER_COMP_DWG_BG 200
#define WIDTH_WIRE 2
#define WIDTH_BUS WIDTH_WIRE
#define WIDTH_LINE 2
#define WIDTH_COMP_DWG 2
#define JUNCTION_R 30
#define NOCONN_LEN 25
#define LABEL_OFFSET 15 // eeschema has more like 10
#define GLABEL_OFFSET 20
#define HLABEL_OFFSET_F 0.4 // * text size
#define PIN_NUM_OFFSET 15 // eeschema has more like 10
#define HSHEET_FIELD_OFFSET 10
#define NEWLINE_SKIP 1.4 // * text size
extern uint32_t color_rgb[];
#endif /* !STYLE_H */

62
eeshow/test.lib Normal file
View File

@ -0,0 +1,62 @@
EESchema-LIBRARY Version 2.3
#encoding utf-8
#
# TEST
#
DEF TEST U 0 40 Y Y 1 F N
F0 "U" -475 675 60 H V C CNN
F1 "TEST" -425 -675 60 H V C CNN
F2 "" 150 200 60 H I C CNN
F3 "" 150 200 60 H I C CNN
DRAW
T 900 1050 -550 100 0 0 0 BLT Normal 1 L T
T 0 900 450 100 0 0 0 NCC Normal 0 C C
T 900 925 -550 100 0 0 0 NCC Normal 0 C C
T 0 900 550 100 0 0 0 NLB Normal 0 L B
T 900 1275 -550 100 0 0 0 NRB Normal 0 R B
T 900 800 -550 100 0 0 0 NRC Normal 0 R C
T 0 900 350 100 0 0 0 NRT Normal 0 R T
P 2 0 0 0 750 -550 1325 -550 N
P 2 0 0 0 800 -425 800 -650 N
P 2 0 0 0 925 -425 925 -650 N
P 2 0 0 0 1050 -425 1050 -650 N
P 2 0 0 0 1275 -425 1275 -650 N
A 975 -50 150 1800 -900 0 1 0 N 825 -50 975 -200
A 975 50 150 1800 900 0 1 0 N 825 50 975 200
A 1075 -50 150 -900 0 0 1 0 N 1075 -200 1225 -50
A 1075 50 150 900 0 0 1 0 N 1075 200 1225 50
C 1025 0 150 0 1 0 N
S -550 600 550 -600 0 1 0 N
P 2 0 1 0 -100 -100 100 100 N
P 2 0 1 0 -100 100 100 -100 N
P 2 0 1 0 825 350 1150 350 N
P 2 0 1 0 825 450 1150 450 N
P 2 0 1 0 825 550 1150 550 N
P 2 0 1 0 900 600 900 275 N
P 3 0 1 0 250 550 450 550 450 400 N
P 10 0 1 0 775 0 775 200 825 250 1225 250 1275 200 1275 -200 1225 -250 825 -250 775 -200 775 0 N
X R_IN 1 -750 500 200 R 50 50 1 1 I
X R_OUT 2 -750 400 200 R 50 50 1 1 O
X R_BIDIR 3 -750 300 200 R 50 50 1 1 O
X R_TRI 4 -750 200 200 R 50 50 1 1 T
X R_PASS 5 -750 100 200 R 50 50 1 1 P
X R_UNSPEC 6 -750 0 200 R 50 50 1 1 U
X R_PIN 7 -750 -100 200 R 50 50 1 1 W
X R_POUT 8 -750 -200 200 R 50 50 1 1 w
X R_OC 9 -750 -300 200 R 50 50 1 1 w
X R_OE 10 -750 -400 200 R 50 50 1 1 w
X D_CLOW 20 0 800 200 D 50 50 1 1 I CL
X R_NC 11 -750 -500 200 R 50 50 1 1 N
X D_ILOW 21 -100 800 200 D 50 50 1 1 I L
X U_LINE 12 -50 -800 200 U 50 50 1 1 I
X U_INV 13 50 -800 200 U 50 50 1 1 I I
X U_CLK 14 150 -800 200 U 50 50 1 1 I C
X U_INVCLK 15 250 -800 200 U 50 50 1 1 I IC
X LEFT 16 750 -325 200 L 50 50 1 1 I
X D_NONLOGIC 17 300 800 200 D 50 50 1 1 I X
X D_FALLING 18 200 800 200 D 50 50 1 1 I F
X D_OLOW 19 100 800 200 D 50 50 1 1 I V
ENDDRAW
ENDDEF
#
#End Library

34
eeshow/test.pro Normal file
View File

@ -0,0 +1,34 @@
update=22/05/2015 07:44:53
version=1
last_client=kicad
[general]
version=1
RootSch=
BoardNm=
[pcbnew]
version=1
LastNetListRead=
UseCmpFile=1
PadDrill=0.600000000000
PadDrillOvalY=0.600000000000
PadSizeH=1.500000000000
PadSizeV=1.500000000000
PcbTextSizeV=1.500000000000
PcbTextSizeH=1.500000000000
PcbTextThickness=0.300000000000
ModuleTextSizeV=1.000000000000
ModuleTextSizeH=1.000000000000
ModuleTextSizeThickness=0.150000000000
SolderMaskClearance=0.000000000000
SolderMaskMinWidth=0.000000000000
DrawSegmentWidth=0.200000000000
BoardOutlineThickness=0.100000000000
ModuleOutlineThickness=0.150000000000
[cvpcb]
version=1
NetIExt=net
[eeschema]
version=1
LibDir=
[eeschema/libraries]
LibName1=test

372
eeshow/test.sch Normal file
View File

@ -0,0 +1,372 @@
EESchema Schematic File Version 2
LIBS:test
LIBS:test-cache
EELAYER 25 0
EELAYER END
$Descr A4 11693 8268
encoding utf-8
Sheet 1 3
Title ""
Date ""
Rev ""
Comp ""
Comment1 ""
Comment2 ""
Comment3 ""
Comment4 ""
$EndDescr
Text Notes 1450 1300 0 100 ~ 0
Text, Right, Normal, 100 mil
Wire Notes Line
1400 1300 1250 1300
Wire Notes Line
1450 1350 1450 1500
Text Notes 3750 1500 2 100 ~ 20
Text, Left, Bold, 100 mil
Wire Notes Line
3800 1500 3950 1500
Wire Notes Line
3750 1550 3750 1700
Text Notes 1050 1550 1 100 Italic 0
Up, Italic
Wire Notes Line
1100 1550 1250 1550
Wire Notes Line
1050 1600 1050 1750
Text Notes 4300 700 3 100 Italic 20
Down, Bold italic
Wire Notes Line
4350 700 4500 700
Wire Notes Line
4300 650 4300 500
Wire Wire Line
4800 1100 5300 1100
Wire Wire Line
5050 850 5050 1350
Wire Wire Line
5550 850 5550 1100
Wire Wire Line
5550 1100 5550 1350
Wire Wire Line
6050 1100 5550 1100
Connection ~ 5550 1100
Wire Bus Line
6750 600 6750 650
Wire Bus Line
6750 650 6750 800
Wire Bus Line
6750 800 6750 900
Wire Bus Line
6750 900 6750 1000
Wire Bus Line
6750 1000 6750 1050
Wire Bus Line
6750 1050 6750 1100
Wire Bus Line
6750 1100 6750 1250
Wire Bus Line
6750 1250 6750 1350
Wire Bus Line
6750 1350 6750 1400
Entry Bus Bus
6650 1250 6750 1350
Wire Bus Line
6200 1250 6650 1250
Wire Wire Line
6650 950 6200 950
Entry Wire Line
6650 950 6750 1050
NoConn ~ 5050 850
NoConn ~ 5050 1350
NoConn ~ 5300 1100
NoConn ~ 4800 1100
Wire Wire Line
1300 2400 2800 2400
Text Label 1300 2400 0 60 ~ 0
LOCAL_RIGHT_NORMAL
Wire Wire Line
1300 2600 2800 2600
Text Label 2800 2600 2 60 ~ 12
LOCAL_LEFT_BOLD
Wire Wire Line
3400 1800 3400 2900
Text Label 3400 2900 1 60 ~ 12
LOCAL_UP_ITALIC
Wire Wire Line
3700 1800 3700 2900
Text Label 3700 1800 3 60 Italic 12
LOCAL_DOWN_BI
Wire Wire Line
4650 2400 5350 2400
Wire Wire Line
4650 2700 5350 2700
Text GLabel 4650 2400 0 60 Input ~ 0
G_R_IN
Text GLabel 5350 2700 2 60 Input ~ 0
G_L_IN
Text GLabel 4650 2700 0 60 Output ~ 0
G_R_OUT
Text GLabel 5350 2400 2 60 Output ~ 0
G_L_OUT
Wire Wire Line
6100 2200 6100 2900
Wire Wire Line
6400 2200 6400 2900
Text GLabel 6100 2200 1 60 BiDi ~ 0
G_UP_BI
Wire Wire Line
4650 3000 4850 3000
Wire Wire Line
4850 3000 5350 3000
Text GLabel 4650 3000 0 60 BiDi ~ 0
G_R_BIDIR
Text GLabel 5350 3000 2 60 UnSpc ~ 0
G_LEFT_PASS
Text GLabel 4650 3150 0 60 UnSpc ~ 0
G_R_TRI
Wire Wire Line
4650 3150 4850 3150
Wire Wire Line
4850 3150 4850 3000
Connection ~ 4850 3000
Text GLabel 6100 2900 3 60 Input ~ 0
G_DOWN_IN
Text GLabel 6400 2200 1 60 Output ~ 0
G_UP_OUT
Text GLabel 6400 2900 3 60 UnSpc ~ 0
G_DOWN_PASS
Wire Wire Line
7250 2700 7950 2700
Wire Wire Line
8750 2200 8750 2900
Wire Wire Line
9050 2200 9050 2900
Wire Wire Line
7250 3150 7450 3150
Wire Wire Line
7450 3150 7450 3000
Connection ~ 7450 3000
Text HLabel 7250 2400 0 60 Input ~ 0
H_R_IN
Text HLabel 7250 2700 0 60 Output ~ 0
H_R_OUT
Text HLabel 7250 3000 0 60 BiDi ~ 0
H_R_BIDIR
Text HLabel 7250 3150 0 60 UnSpc ~ 0
H_R_TRI
Text HLabel 7950 2400 2 60 Output ~ 0
H_L_OUT
Text HLabel 7950 2700 2 60 Input ~ 0
H_L_IN
Wire Wire Line
7250 2400 7950 2400
Text HLabel 7950 3000 2 60 UnSpc ~ 0
H_LEFT_PASS
Text HLabel 8750 2200 1 60 BiDi ~ 0
H_UP_BI
Text HLabel 8750 2900 3 60 Input ~ 0
H_DOWN_IN
Text HLabel 9050 2200 1 60 Output ~ 0
H_UP_OUT
Text HLabel 9050 2900 3 60 UnSpc ~ 0
H_DOWN_PASS
Wire Wire Line
7250 3000 7450 3000
Wire Wire Line
7450 3000 7950 3000
Text Notes 1300 3400 0 60 ~ 0
60 mil Text
Wire Notes Line
1300 3150 1300 3550
Wire Notes Line
1850 3550 1850 3150
Wire Notes Line
1150 3300 2000 3300
Wire Notes Line
1150 3400 2000 3400
Text GLabel 1400 3750 2 60 Output ~ 0
GLOBAL
Text GLabel 1800 3950 0 60 Output ~ 0
GLOBAL
Wire Notes Line
1400 3550 1400 4150
Wire Notes Line
1800 3550 1800 4150
Wire Notes Line
1250 3700 1950 3700
Wire Notes Line
1250 3800 1950 3800
Wire Notes Line
1250 3900 1950 3900
Wire Notes Line
1250 4000 1950 4000
Text HLabel 2950 3600 0 60 Input ~ 0
HIERARCHICAL
Text HLabel 2250 3750 2 60 Input ~ 0
HIERARCHICAL
Wire Notes Line
2250 3400 2250 3950
Wire Notes Line
2100 3700 3100 3700
Wire Notes Line
2100 3650 3100 3650
Wire Notes Line
2100 3550 3100 3550
Wire Notes Line
2100 3800 3100 3800
Wire Notes Line
2950 3400 2950 3950
$Comp
L TEST U?
U 1 1 57933A17
P 1650 5200
F 0 "U?" H 1175 5875 60 0000 C CNN
F 1 "TEST" H 1225 4525 60 0000 C CNN
F 2 "" H 1800 5400 60 0001 C CNN
F 3 "" H 1800 5400 60 0001 C CNN
1 1650 5200
1 0 0 -1
$EndComp
$Comp
L TEST U?
U 1 1 57933A5F
P 4650 4750
F 0 "U?" H 4175 5425 60 0000 C CNN
F 1 "TEST" H 4225 4075 60 0000 C CNN
F 2 "" H 4800 4950 60 0001 C CNN
F 3 "" H 4800 4950 60 0001 C CNN
1 4650 4750
0 1 1 0
$EndComp
$Comp
L TEST U?
U 1 1 57933A97
P 7450 4900
F 0 "U?" H 6975 5575 60 0000 C CNN
F 1 "TEST" H 7025 4225 60 0000 C CNN
F 2 "" H 7600 5100 60 0001 C CNN
F 3 "" H 7600 5100 60 0001 C CNN
1 7450 4900
-1 0 0 1
$EndComp
$Comp
L TEST U?
U 1 1 57933ACD
P 9750 5250
F 0 "U?" H 9275 5925 60 0000 C CNN
F 1 "TEST" H 9325 4575 60 0000 C CNN
F 2 "" H 9900 5450 60 0001 C CNN
F 3 "" H 9900 5450 60 0001 C CNN
1 9750 5250
0 -1 -1 0
$EndComp
$Comp
L TEST U?
U 1 1 57933B03
P 2450 6950
F 0 "U?" H 1975 7625 60 0000 C CNN
F 1 "TEST" H 2025 6275 60 0000 C CNN
F 2 "" H 2600 7150 60 0001 C CNN
F 3 "" H 2600 7150 60 0001 C CNN
1 2450 6950
1 0 0 1
$EndComp
$Comp
L TEST U?
U 1 1 57933B47
P 5950 6900
F 0 "U?" H 5475 7575 60 0000 C CNN
F 1 "TEST" H 5525 6225 60 0000 C CNN
F 2 "" H 6100 7100 60 0001 C CNN
F 3 "" H 6100 7100 60 0001 C CNN
1 5950 6900
-1 0 0 -1
$EndComp
Text Notes 900 7000 0 60 ~ 0
X-flip
Text Notes 4250 6900 0 60 ~ 0
Y-flip
$Comp
L TEST U?
U 1 1 57933BAB
P 10200 2400
F 0 "U?" H 9725 3075 60 0000 C CNN
F 1 "TEST" H 9775 1725 60 0000 C CNN
F 2 "" H 10350 2600 60 0001 C CNN
F 3 "" H 10350 2600 60 0001 C CNN
1 10200 2400
0 1 -1 0
$EndComp
Text Notes 10000 850 0 60 ~ 0
R+X
$Sheet
S 7250 790 800 560
U 579BE133
F0 "Sheet579BE132" 60
F1 "file579BE132.sch" 60
$EndSheet
$Sheet
S 7190 1790 770 400
U 579BE13D
F0 "Sheet579BE13C" 60
F1 "file579BE13C.sch" 60
$EndSheet
Wire Bus Line
6200 1200 6650 1200
Entry Bus Bus
6650 1200 6750 1100
Wire Wire Line
6650 900 6200 900
Entry Wire Line
6650 900 6750 800
Wire Wire Line
6850 750 7100 750
Wire Wire Line
6850 800 7100 800
Entry Wire Line
6750 900 6850 800
Entry Wire Line
6750 650 6850 750
Entry Bus Bus
6750 1250 6850 1150
Entry Bus Bus
6750 1000 6850 1100
Wire Bus Line
7100 1100 6850 1100
Wire Bus Line
7100 1150 6850 1150
Wire Bus Line
4750 1950 5700 1950
Wire Wire Line
4850 1850 4850 1500
Wire Bus Line
4950 1850 4950 1500
Wire Wire Line
5400 1850 5400 1500
Wire Bus Line
5500 1500 5500 1850
Wire Wire Line
4800 2250 4800 2050
Wire Wire Line
5300 2250 5300 2050
Wire Bus Line
5450 2250 5450 2050
Wire Bus Line
4900 2250 4900 2050
Entry Wire Line
4850 1850 4950 1950
Entry Wire Line
5200 1950 5300 2050
Entry Wire Line
4800 2050 4900 1950
Entry Wire Line
5300 1950 5400 1850
Entry Bus Bus
4950 1850 5050 1950
Entry Bus Bus
4900 2050 5000 1950
Entry Bus Bus
5400 1950 5500 1850
Entry Bus Bus
5350 1950 5450 2050
$EndSCHEMATC

24
eeshow/test/README Normal file
View File

@ -0,0 +1,24 @@
Setup
-----
git clone https://neo900.org/git/ee.git neo900-ee
cd neo900-ee
git reset --hard 57eebdcf573311c049bc57527bc03a517aff0fef
cd ..
git clone git://projects.qi-hardware.com/kicad-libs.git
cd kicad-libs
git reset --hard 143fa7fe10cabbfe1cb12d010c7426d482d7e6f4
cd ..
./genpng ref
Run test
--------
./genpng
./comp
qiv -t _diff*.png

29
eeshow/test/comp Executable file
View File

@ -0,0 +1,29 @@
#!/bin/sh
usage()
{
echo "usage: $0 [dir]" 1>&2
exit 1
}
[ "$2" ] && usage
[ "${1#-}" != "$1" ] && usage
dir=${1:-.}
diffs=0
rm -f $dir/_diff*png
for n in $dir/out*.png; do
out=`basename "$n"`
ref=$dir/ref${out#out}
diff=$dir/_diff${out#out}
if ! compare -metric AE $ref $n - >/dev/null; then
diffs=`expr $diffs + 1`
compare -metric AE $ref $n $diff
fi
done
echo
[ $diffs = 0 ] && exit 0
echo "$diffs difference(s)" 1>&2
exit 1

37
eeshow/test/genpng Executable file
View File

@ -0,0 +1,37 @@
#!/bin/sh
usage()
{
echo "usage: $0 [[dir] prefix]" 1>&2
exit 1
}
[ "$3" ] && usage
[ "${1#-}" != "$1" ] && usage
dir=.
if [ "$2" ]; then
dir=$1
shift
fi
prefix=${1:-out}
sheet=1
while [ $sheet -le 38 ]; do
echo -n .
sn=`printf '%02d' $sheet`
file=$dir/$prefix$sn.png
if [ $sheet = 1 ]; then
in=$dir/neo900-ee/hw/neo900.sch
else
in=$dir/neo900-ee/hw/neo900_SS_`expr $sheet - 1`.sch
fi
file=$dir/$prefix$sn.png
$dir/../eeshow $dir/neo900-ee/hw/neo900.lib \
$dir/kicad-libs/components/powered.lib "$in" \
-- fig -t $dir/frame.fig SHEET=$sn |
fig2dev -L png -m 2 >$file
sheet=`expr $sheet + 1`
done
echo

158
eeshow/text.c Normal file
View File

@ -0,0 +1,158 @@
/*
* text.c - FIG text object
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "util.h"
#include "misc.h"
#include "style.h"
#include "gfx.h"
#include "text.h"
void text_init(struct text *txt)
{
txt->s = NULL;
txt->size = 0;
txt->x = txt->y = 0;
txt->rot = 0;
txt->hor = text_mid;
txt->vert = text_mid;
}
void text_free(struct text *txt)
{
free((void *) txt->s);
txt->s = NULL;
}
void text_set(struct text *txt, const char *s)
{
free((void *) txt->s);
txt->s = stralloc(s);
}
void text_rot(struct text *txt, int deg)
{
txt->rot = angle_add(txt->rot, deg);
}
enum text_align text_flip(enum text_align align)
{
switch (align) {
case text_min:
return text_max;
case text_mid:
return text_mid;
case text_max:
return text_min;
default:
abort();
}
}
void text_flip_x(struct text *txt)
{
txt->rot = angle_add(txt->rot, 180);
txt->hor = text_flip(txt->hor);
// @@@ flip vert, too ?
}
static int align(int dim, enum text_align align)
{
switch (align) {
case text_min:
return 0;
case text_mid:
return dim / 2;
case text_max:
return dim;
default:
abort();
}
}
void text_fig(const struct text *txt, int color, unsigned layer)
{
char *buf = stralloc(txt->s);
char *tmp = buf;
const char *s;
int x = txt->x;
int y = txt->y;
x += rx(0, align(txt->size, txt->vert), txt->rot);
y += ry(0, align(txt->size, txt->vert), txt->rot);
while (1) {
s = strtok(tmp, "\n");
if (!s)
break;
tmp = NULL;
gfx_text(x, y, s, txt->size, txt->hor, txt->rot, color, layer);
x += rx(0, NEWLINE_SKIP * txt->size, txt->rot);
y += ry(0, NEWLINE_SKIP * txt->size, txt->rot);
}
free(buf);
}
void text_rel(const struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy, int *res_x, int *res_y)
{
int width = gfx_text_width(txt->s, txt->size);
dx -= align(width, txt->hor);
dy += align(txt->size, txt->vert);
dx += align(width, xr);
dy -= align(txt->size, yr);
if (res_x)
*res_x = txt->x + rx(dx, dy, txt->rot);
if (res_y)
*res_y = txt->y + ry(dx, dy, txt->rot);
}
void text_shift(struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy)
{
text_rel(txt, xr, yr, dx, dy, &txt->x, &txt->y);
}
int text_rel_x(const struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy)
{
int x;
text_rel(txt, xr, yr, dx, dy, &x, NULL);
return x;
}
int text_rel_y(const struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy)
{
int y;
text_rel(txt, xr, yr, dx, dy, NULL, &y);
return y;
}

58
eeshow/text.h Normal file
View File

@ -0,0 +1,58 @@
/*
* text.h - FIG text object
*
* Written 2016 by Werner Almesberger
* Copyright 2016 by Werner Almesberger
*
* 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 TEXT_H
#define TEXT_H
/* use constants of FIG text sub_type */
enum text_align {
text_min = 0, // left or bottom
text_mid = 1, // center
text_max = 2, // right or top
};
enum text_style {
text_normal,
};
struct text {
const char *s;
int size;
int x, y;
int rot;
enum text_align hor;
enum text_align vert;
};
void text_init(struct text *txt);
void text_free(struct text *txt);
void text_set(struct text *txt, const char *s);
void text_rot(struct text *txt, int deg);
void text_flip_x(struct text *txt);
enum text_align text_flip(enum text_align align);
void text_fig(const struct text *txt, int color, unsigned layer);
void text_rel(const struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy, int *res_x, int *res_y);
void text_shift(struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy);
int text_rel_x(const struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy);
int text_rel_y(const struct text *txt, enum text_align xr, enum text_align yr,
int dx, int dy);
#endif /* !TEXT_H */

52
eeshow/util.h Normal file
View File

@ -0,0 +1,52 @@
/*
* util.h - Common utility functions
*
* Written 2016 by Werner Almesberger
* Copyright 2016 Werner Almesberger
*
* 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 UTIL_H
#define UTIL_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define alloc_size(s) \
({ void *alloc_size_tmp = malloc(s); \
if (!alloc_size_tmp) { \
perror("malloc"); \
exit(1); \
} \
alloc_size_tmp; })
#define alloc_type(t) ((t *) alloc_size(sizeof(t)))
#define stralloc(s) \
({ char *stralloc_tmp = strdup(s); \
if (!stralloc_tmp) { \
perror("strdup"); \
exit(1); \
} \
stralloc_tmp; })
#define ARRAY_ELEMENTS(a) (sizeof(a) / sizeof(a[0]))
#define ARRAY_END(a) ((a) + ARRAY_ELEMENTS(a))
#define swap(a, b) \
({ typeof(a) _tmp = (a); a = (b); b = _tmp; })
#define unsupported(s) \
fprintf(stderr, __FILE__ ":%d: unsupported: " s "\n", __LINE__)
#endif /* !UTIL_H */