mirror of
git://projects.qi-hardware.com/eda-tools.git
synced 2024-11-22 15:10:38 +02:00
rename sch2fig to eeshow
This commit is contained in:
parent
590724e3bb
commit
a941a5f246
25
eeshow/DEMO
Normal file
25
eeshow/DEMO
Normal 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
91
eeshow/Makefile
Normal 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
24
eeshow/TODO
Normal 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
461
eeshow/cro.c
Normal 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
31
eeshow/cro.h
Normal 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
279
eeshow/diff.c
Normal 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
22
eeshow/diff.h
Normal 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
463
eeshow/dwg.c
Normal 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
46
eeshow/dwg.h
Normal 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
293
eeshow/fig.c
Normal 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
22
eeshow/fig.h
Normal 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
76
eeshow/file.c
Normal 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
22
eeshow/file.h
Normal 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
120
eeshow/gfx.c
Normal 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
72
eeshow/gfx.h
Normal 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
371
eeshow/git-file.c
Normal 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
22
eeshow/git-file.h
Normal 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
268
eeshow/lib-parse.c
Normal 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
396
eeshow/lib-render.c
Normal 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
124
eeshow/lib.h
Normal 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
172
eeshow/main.c
Normal 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
31
eeshow/main.h
Normal 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
114
eeshow/misc.c
Normal 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
51
eeshow/misc.h
Normal 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 */
|
15
eeshow/neo900-template.fig
Normal file
15
eeshow/neo900-template.fig
Normal 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
342
eeshow/record.c
Normal 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
58
eeshow/record.h
Normal 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
562
eeshow/sch-parse.c
Normal 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
174
eeshow/sch-render.c
Normal 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
123
eeshow/sch.h
Normal 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
92
eeshow/sch2pdf
Executable 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
31
eeshow/style.c
Normal 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
91
eeshow/style.h
Normal 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
62
eeshow/test.lib
Normal 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
34
eeshow/test.pro
Normal 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
372
eeshow/test.sch
Normal 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
24
eeshow/test/README
Normal 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
29
eeshow/test/comp
Executable 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
37
eeshow/test/genpng
Executable 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
158
eeshow/text.c
Normal 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
58
eeshow/text.h
Normal 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
52
eeshow/util.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user