mirror of
git://projects.qi-hardware.com/eda-tools.git
synced 2025-04-21 12:27:27 +03:00
eeshow/: move graphics low-level functions to gfx/
This commit is contained in:
607
eeshow/gfx/cro.c
Normal file
607
eeshow/gfx/cro.c
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* gfx/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 "diag.h"
|
||||
#include "gfx/style.h"
|
||||
#include "gfx/text.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/record.h"
|
||||
#include "main.h"
|
||||
#include "gfx/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; /* offset in target (e.g., canvas) coord */
|
||||
int xe, ye; /* additional offset in eeschema coord */
|
||||
float scale;
|
||||
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *s;
|
||||
|
||||
struct record *sheets; /* for PDF */
|
||||
unsigned n_sheets;
|
||||
|
||||
const char *output_name;
|
||||
|
||||
int color_override; /* FIG color, COLOR_NONE if no override */
|
||||
};
|
||||
|
||||
|
||||
static inline int cd(const struct cro_ctx *cc, int x)
|
||||
{
|
||||
return x * cc->scale;
|
||||
}
|
||||
|
||||
|
||||
static inline int cx(const struct cro_ctx *cc, int x)
|
||||
{
|
||||
return cc->xo + (x + cc->xe) * cc->scale;
|
||||
}
|
||||
|
||||
|
||||
static inline int xc(const struct cro_ctx *cc, int x)
|
||||
{
|
||||
return (x - cc->xe) / cc->scale - cc->xe;
|
||||
}
|
||||
|
||||
|
||||
static inline int cy(const struct cro_ctx *cc, int y)
|
||||
{
|
||||
return cc->yo + (y + cc->ye) * cc->scale;
|
||||
}
|
||||
|
||||
|
||||
static inline float pt(const struct cro_ctx *cc, int x)
|
||||
{
|
||||
return cd(cc, x) * 72 * 1.5 / 1200.0;
|
||||
}
|
||||
|
||||
|
||||
static void set_color(struct cro_ctx *cc, int color)
|
||||
{
|
||||
uint32_t c;
|
||||
|
||||
if (cc->color_override != COLOR_NONE)
|
||||
color = cc->color_override;
|
||||
if (color < 0)
|
||||
return;
|
||||
c = color_rgb[color];
|
||||
cairo_set_source_rgb(cc->cr,
|
||||
(c >> 16) / 255.0, ((c >> 8) & 255) / 255.0, (c & 255) / 255.0);
|
||||
}
|
||||
|
||||
|
||||
static void paint(struct cro_ctx *cc, int color, int fill_color)
|
||||
{
|
||||
if (fill_color != COLOR_NONE) {
|
||||
set_color(cc, fill_color);
|
||||
if (color == COLOR_NONE)
|
||||
cairo_fill(cc->cr);
|
||||
else
|
||||
cairo_fill_preserve(cc->cr);
|
||||
}
|
||||
if (color != COLOR_NONE) {
|
||||
set_color(cc, color);
|
||||
cairo_stroke(cc->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[] = { 2, 4 };
|
||||
|
||||
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, 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, 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, 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);
|
||||
if (fill_color != COLOR_NONE)
|
||||
cairo_close_path(cc->cr);
|
||||
paint(cc, 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, 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 */
|
||||
}
|
||||
|
||||
|
||||
/* ----- Color override ---------------------------------------------------- */
|
||||
|
||||
|
||||
void cro_color_override(struct cro_ctx *cc, int color)
|
||||
{
|
||||
cc->color_override = color;
|
||||
}
|
||||
|
||||
|
||||
/* ----- Initialization 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 *new_cc(void)
|
||||
{
|
||||
struct cro_ctx *cc;
|
||||
|
||||
cc = alloc_type(struct cro_ctx);
|
||||
cc->xo = cc->yo = 0;
|
||||
cc->xe = cc->ye = 0;
|
||||
cc->scale = DEFAULT_SCALE;
|
||||
|
||||
cc->sheets = NULL;
|
||||
cc->n_sheets = 0;
|
||||
|
||||
cc->color_override = COLOR_NONE;
|
||||
|
||||
cc->output_name = NULL;
|
||||
|
||||
/*
|
||||
* record_init does not perform allocations or such, so it's safe to
|
||||
* call it here even if we don't use this facility.
|
||||
*/
|
||||
record_init(&cc->record, &real_cro_ops, cc);
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
static struct cro_ctx *init_common(int argc, char *const *argv)
|
||||
{
|
||||
struct cro_ctx *cc = new_cc();
|
||||
char c;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
||||
|
||||
void cro_get_size(const struct cro_ctx *cc, int *w, int *h, int *x, int *y)
|
||||
{
|
||||
int xmin, ymin;
|
||||
|
||||
record_bbox(&cc->record, &xmin, &ymin, w, h);
|
||||
|
||||
// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, xmin, ymin);
|
||||
*x = xmin;
|
||||
*y = ymin;
|
||||
*w = cd(cc, *w);
|
||||
*h = cd(cc, *h);
|
||||
// fprintf(stderr, "%dx%d%+d%+d\n", *w, *h, xmin, ymin);
|
||||
}
|
||||
|
||||
|
||||
static void end_common(struct cro_ctx *cc, int *w, int *h, int *x, int *y)
|
||||
{
|
||||
int xmin, ymin;
|
||||
|
||||
cairo_surface_destroy(cc->s);
|
||||
cairo_destroy(cc->cr);
|
||||
|
||||
cro_get_size(cc, w, h, &xmin, &ymin);
|
||||
cc->xo = -cd(cc, xmin);
|
||||
cc->yo = -cd(cc, ymin);
|
||||
|
||||
if (x)
|
||||
*x = xmin;
|
||||
if (y)
|
||||
*y = ymin;
|
||||
}
|
||||
|
||||
|
||||
static cairo_status_t stream_to_stdout(void *closure,
|
||||
const unsigned char *data, unsigned length)
|
||||
{
|
||||
ssize_t wrote;
|
||||
|
||||
wrote = write(1, data, length);
|
||||
if (wrote == (ssize_t) length)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
diag_perror("stdout");
|
||||
return CAIRO_STATUS_WRITE_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* ----- PDF (auto-sizing, using redraw) ----------------------------------- */
|
||||
|
||||
|
||||
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 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)
|
||||
diag_pfatal("realloc");
|
||||
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, NULL, NULL);
|
||||
|
||||
if (cc->output_name)
|
||||
cc->s = cairo_pdf_surface_create(cc->output_name, w, h);
|
||||
else
|
||||
cc->s = cairo_pdf_surface_create_for_stream(stream_to_stdout,
|
||||
NULL, 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, 0.5 * cc->scale);
|
||||
/* @@@ CAIRO_LINE_CAP_ROUND makes all non-dashed lines disappear */
|
||||
cairo_set_line_cap(cc->cr, CAIRO_LINE_CAP_SQUARE);
|
||||
|
||||
for (i = 0; i != cc->n_sheets; i++) {
|
||||
set_color(cc, 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);
|
||||
}
|
||||
|
||||
|
||||
/* ----- PNG (auto-sizing, using redraw) ----------------------------------- */
|
||||
|
||||
|
||||
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_png_end(void *ctx)
|
||||
{
|
||||
struct cro_ctx *cc = ctx;
|
||||
int w, h, stride;
|
||||
|
||||
cro_img_end(cc, &w, &h, &stride);
|
||||
cro_img_write(cc, cc->output_name);
|
||||
}
|
||||
|
||||
|
||||
/* ----- Images (auto-sizing, using redraw) -------------------------------- */
|
||||
|
||||
|
||||
uint32_t *cro_img_end(struct cro_ctx *cc, int *w, int *h, int *stride)
|
||||
{
|
||||
uint32_t *data;
|
||||
|
||||
end_common(cc, w, h, NULL, NULL);
|
||||
|
||||
*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, 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);
|
||||
cairo_set_line_cap(cc->cr, CAIRO_LINE_CAP_ROUND);
|
||||
|
||||
record_replay(&cc->record);
|
||||
record_destroy(&cc->record);
|
||||
|
||||
cairo_surface_flush(cc->s);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void cro_img_write(struct cro_ctx *cc, const char *name)
|
||||
{
|
||||
if (name)
|
||||
cairo_surface_write_to_png(cc->s, name);
|
||||
else
|
||||
cairo_surface_write_to_png_stream(cc->s, stream_to_stdout,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
/* ----- Canvas (using redraw) --------------------------------------------- */
|
||||
|
||||
|
||||
void cro_canvas_end(struct cro_ctx *cc, int *w, int *h, int *xmin, int *ymin)
|
||||
{
|
||||
end_common(cc, w, h, xmin, ymin);
|
||||
*w /= cc->scale;
|
||||
*h /= cc->scale;
|
||||
}
|
||||
|
||||
|
||||
void cro_canvas_prepare(cairo_t *cr)
|
||||
{
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
cairo_paint(cr);
|
||||
|
||||
cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_BOLD);
|
||||
|
||||
cairo_set_line_width(cr, 2);
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||
}
|
||||
|
||||
|
||||
void cro_canvas_draw(struct cro_ctx *cc, cairo_t *cr, int xo, int yo,
|
||||
float scale)
|
||||
{
|
||||
cc->cr = cr;
|
||||
|
||||
cc->scale = scale;
|
||||
cc->xo = xo;
|
||||
cc->yo = yo;
|
||||
record_replay(&cc->record);
|
||||
}
|
||||
|
||||
|
||||
/* ----- Image for external use (simplified API) --------------------------- */
|
||||
|
||||
|
||||
uint32_t *cro_img(struct cro_ctx *ctx, int xo, int yo, int w, int h,
|
||||
int xe, int ye,
|
||||
float scale, cairo_t **res_cr, int *res_stride)
|
||||
{
|
||||
int stride;
|
||||
uint32_t *data;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *s;
|
||||
|
||||
stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w);
|
||||
data = alloc_size(stride * h);
|
||||
|
||||
s = cairo_image_surface_create_for_data((unsigned char *) data,
|
||||
CAIRO_FORMAT_RGB24, w, h, stride);
|
||||
cr = cairo_create(s);
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
cairo_paint(cr);
|
||||
|
||||
cairo_select_font_face(cr, "Helvetica", CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_BOLD);
|
||||
cairo_set_line_width(cr, 2);
|
||||
cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
|
||||
|
||||
ctx->cr = cr;
|
||||
ctx->s = s;
|
||||
ctx->xo = xo;
|
||||
ctx->yo = yo;
|
||||
ctx->xe = xe;
|
||||
ctx->ye = ye;
|
||||
ctx->scale = scale;
|
||||
ctx->color_override = COLOR_NONE;
|
||||
|
||||
record_replay(&ctx->record);
|
||||
|
||||
if (res_cr)
|
||||
*res_cr = cr;
|
||||
if (res_stride)
|
||||
*res_stride = stride;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/* ----- 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,
|
||||
};
|
||||
50
eeshow/gfx/cro.h
Normal file
50
eeshow/gfx/cro.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* gfx/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 GFX_CRO_H
|
||||
#define GFX_CRO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
#include "gfx/gfx.h"
|
||||
|
||||
|
||||
struct cro_ctx;
|
||||
|
||||
|
||||
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 */
|
||||
#define cro_canvas_ops cro_png_ops /* just don't call cro_canvas_ops.end */
|
||||
|
||||
|
||||
void cro_color_override(struct cro_ctx *cc, int color);
|
||||
|
||||
void cro_get_size(const struct cro_ctx *cc, int *w, int *h, int *x, int *y);
|
||||
|
||||
uint32_t *cro_img_end(struct cro_ctx *cc, int *w, int *h, int *stride);
|
||||
void cro_img_write(struct cro_ctx *cc, const char *name);
|
||||
|
||||
void cro_canvas_end(struct cro_ctx *cc, int *w, int *h, int *xmin, int *ymin);
|
||||
void cro_canvas_prepare(cairo_t *cr);
|
||||
void cro_canvas_draw(struct cro_ctx *cc, cairo_t *cr,
|
||||
int x, int y, float scale);
|
||||
|
||||
uint32_t *cro_img(struct cro_ctx *ctx, int x0, int yo, int w, int h,
|
||||
int xe, int ye,
|
||||
float scale, cairo_t **res_cr, int *res_stride);
|
||||
|
||||
#endif /* !GFX_CRO_H */
|
||||
401
eeshow/gfx/diff.c
Normal file
401
eeshow/gfx/diff.c
Normal file
@@ -0,0 +1,401 @@
|
||||
/*
|
||||
* gfx/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 <cairo/cairo.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "diag.h"
|
||||
#include "main.h"
|
||||
#include "gfx/cro.h"
|
||||
#include "file/file.h"
|
||||
#include "kicad/sch.h"
|
||||
#include "kicad/lib.h"
|
||||
#include "gfx/record.h"
|
||||
#include "gfx/diff.h"
|
||||
|
||||
|
||||
#define DEFAULT_FRAME_RADIUS 30
|
||||
|
||||
#define FADE_SHIFT 3
|
||||
#define FADE_MASK ((0xff >> FADE_SHIFT) * (0x010101))
|
||||
#define FADE_OFFSET (~FADE_MASK & 0xffffff)
|
||||
|
||||
#define MASK 0xffffff
|
||||
|
||||
/* steal from schhist/ppmdiff.c */
|
||||
|
||||
#define ONLY_OLD 0xff5050
|
||||
#define ONLY_NEW 0x00c000
|
||||
#define BOTH 0x707070
|
||||
|
||||
#define AREA_FILL 0xffd0f0
|
||||
|
||||
|
||||
|
||||
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 file sch_file;
|
||||
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);
|
||||
|
||||
if (!file_open(&sch_file, argv[argc - 1], NULL))
|
||||
goto fail_open;
|
||||
for (arg = optind; arg != argc - 1; arg++)
|
||||
if (!lib_parse(&new_lib, argv[arg], &sch_file))
|
||||
goto fail_parse;
|
||||
if (!sch_parse(&new_sch, &sch_file, &new_lib, NULL))
|
||||
goto fail_parse;
|
||||
file_close(&sch_file);
|
||||
|
||||
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;
|
||||
|
||||
fail_parse:
|
||||
file_close(&sch_file);
|
||||
fail_open:
|
||||
sch_free(&new_sch);
|
||||
lib_free(&new_lib);
|
||||
free(diff);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static void differences(struct diff *diff, uint32_t *a, const uint32_t *b)
|
||||
{
|
||||
unsigned skip = diff->w * 4 - diff->stride;
|
||||
int x, y;
|
||||
|
||||
for (y = 0; y != diff->h; y++) {
|
||||
for (x = 0; x != diff->w; x++) {
|
||||
if (!((*a ^ *b) & MASK)) {
|
||||
*a = ((*a >> FADE_SHIFT) & FADE_MASK) |
|
||||
FADE_OFFSET;
|
||||
} else {
|
||||
mark_area(diff, x, y);
|
||||
*a = (*a & MASK) == MASK ? ONLY_NEW :
|
||||
(*b & MASK) == MASK ? ONLY_OLD : BOTH;
|
||||
}
|
||||
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 free_areas(struct diff *diff)
|
||||
{
|
||||
struct area *next;
|
||||
|
||||
while (diff->areas) {
|
||||
next = diff->areas->next;
|
||||
free(diff->areas);
|
||||
diff->areas = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
fatal("%d x %d vs. %d x %d image\n", w, h, diff->w, diff->h);
|
||||
|
||||
differences(diff, old_img, diff->new_img);
|
||||
show_areas(diff, old_img);
|
||||
free_areas(diff);
|
||||
|
||||
cro_img_write(diff->cr_ctx, diff->output_name);
|
||||
}
|
||||
|
||||
|
||||
/* ----- Diff to canvas ---------------------------------------------------- */
|
||||
|
||||
|
||||
static void merge_coord(int pos_a, int pos_b, int dim_a, int dim_b,
|
||||
int *pos_res, int *res_dim)
|
||||
{
|
||||
if (pos_a < pos_b) {
|
||||
*pos_res = pos_a;
|
||||
dim_b += pos_b - pos_a;
|
||||
} else {
|
||||
*pos_res = pos_a;
|
||||
dim_a += pos_a - pos_b;
|
||||
}
|
||||
*res_dim = dim_a > dim_b ? dim_a : dim_b;
|
||||
}
|
||||
|
||||
|
||||
void diff_to_canvas(cairo_t *cr, int cx, int cy, float scale,
|
||||
struct cro_ctx *old, struct cro_ctx *new)
|
||||
{
|
||||
int old_xmin, old_ymin, old_w, old_h;
|
||||
int new_xmin, new_ymin, new_w, new_h;
|
||||
int xmin, ymin, w, h, stride;
|
||||
uint32_t *img_old, *img_new;
|
||||
double x1, y1, x2, y2;
|
||||
int sw, sh;
|
||||
cairo_t *old_cr;
|
||||
cairo_surface_t *s;
|
||||
|
||||
cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
|
||||
sw = x2 - x1;
|
||||
sh = y2 - y1;
|
||||
|
||||
/* @@@ baeh ! */
|
||||
record_bbox((const struct record *) old,
|
||||
&old_xmin, &old_ymin, &old_w, &old_h);
|
||||
record_bbox((const struct record *) new,
|
||||
&new_xmin, &new_ymin, &new_w, &new_h);
|
||||
|
||||
merge_coord(old_xmin, new_xmin, old_w, new_w, &xmin, &w);
|
||||
merge_coord(old_ymin, new_ymin, old_h, new_h, &ymin, &h);
|
||||
|
||||
/*
|
||||
* We use two sets of offset differences: one applied to eeschema
|
||||
* coordinates (the xe, ye pair), and one applied to canvas coordinates
|
||||
* (the xo, yo pair).
|
||||
*
|
||||
* This is to prevent different offsets from leading to rounding
|
||||
* differences, resulting in single-pixel differences, which in turn
|
||||
* the differences algorithm will be eager to mark with big yellow
|
||||
* boxes.
|
||||
*/
|
||||
img_old = cro_img(old,
|
||||
sw / 2.0 - (cx + xmin) * scale,
|
||||
sh / 2.0 - (cy + ymin) * scale,
|
||||
sw, sh,
|
||||
xmin - old_xmin,
|
||||
ymin - old_ymin,
|
||||
scale, &old_cr, &stride);
|
||||
img_new = cro_img(new,
|
||||
sw / 2.0 - (cx + xmin) * scale,
|
||||
sh / 2.0 - (cy + ymin) * scale,
|
||||
sw, sh,
|
||||
xmin - new_xmin,
|
||||
ymin - new_ymin,
|
||||
scale, NULL, NULL);
|
||||
|
||||
struct diff diff = {
|
||||
.w = sw,
|
||||
.h = sh,
|
||||
.stride = stride,
|
||||
.frame_radius = DEFAULT_FRAME_RADIUS,
|
||||
.areas = NULL,
|
||||
};
|
||||
|
||||
s = cairo_get_target(old_cr);
|
||||
cairo_surface_flush(s);
|
||||
differences(&diff, img_old, img_new);
|
||||
show_areas(&diff, img_old);
|
||||
cairo_surface_mark_dirty(s);
|
||||
|
||||
free_areas(&diff);
|
||||
|
||||
cairo_set_source_surface(cr, s, 0, 0);
|
||||
cairo_paint(cr);
|
||||
|
||||
cairo_surface_destroy(s);
|
||||
cairo_destroy(old_cr);
|
||||
free(img_old);
|
||||
free(img_new);
|
||||
}
|
||||
|
||||
|
||||
/* ----- 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,
|
||||
};
|
||||
29
eeshow/gfx/diff.h
Normal file
29
eeshow/gfx/diff.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* gfx/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 GFX_DIFF_H
|
||||
#define GFX_DIFF_H
|
||||
|
||||
#include <cairo/cairo.h>
|
||||
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/cro.h"
|
||||
|
||||
|
||||
extern const struct gfx_ops diff_ops;
|
||||
|
||||
|
||||
void diff_to_canvas(cairo_t *cr, int cx, int cy, float scale,
|
||||
struct cro_ctx *old, struct cro_ctx *new);
|
||||
|
||||
#endif /* !GFX_DIFF_H */
|
||||
310
eeshow/gfx/fig.c
Normal file
310
eeshow/gfx/fig.c
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* gfx/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 "diag.h"
|
||||
#include "gfx/style.h"
|
||||
#include "gfx/text.h"
|
||||
#include "main.h"
|
||||
#include "gfx/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");
|
||||
}
|
||||
|
||||
|
||||
static void fig_colors(void)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 32; i != n_color_rgb; i++)
|
||||
printf("0 %d #%06x\n", i, color_rgb[i]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
static char *buf = NULL;
|
||||
static size_t n = 0;
|
||||
const char *template = NULL;
|
||||
const char **vars = NULL;
|
||||
int n_vars = 0;
|
||||
char c;
|
||||
int arg;
|
||||
FILE *file;
|
||||
int lines_to_colors = 8;
|
||||
|
||||
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();
|
||||
fig_colors();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
file = fopen(template, "r");
|
||||
if (!file)
|
||||
diag_pfatal(template);
|
||||
while (getline(&buf, &n, file) > 0) {
|
||||
while (apply_vars(buf, n_vars, vars));
|
||||
printf("%s", buf);
|
||||
if (*buf == '#')
|
||||
continue;
|
||||
if (!--lines_to_colors)
|
||||
fig_colors();
|
||||
/*
|
||||
* @@@ known bug: if the template is empty, we won't output
|
||||
* color 32.
|
||||
*/
|
||||
}
|
||||
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/gfx/fig.h
Normal file
22
eeshow/gfx/fig.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* gfx/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 GFX_FIG_H
|
||||
#define GFX_FIG_H
|
||||
|
||||
#include "gfx/gfx.h"
|
||||
|
||||
|
||||
extern const struct gfx_ops fig_ops;
|
||||
|
||||
#endif /* !GFX_FIG_H */
|
||||
120
eeshow/gfx/gfx.c
Normal file
120
eeshow/gfx/gfx.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* gfx/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 "gfx/style.h"
|
||||
#include "gfx/text.h"
|
||||
#include "gfx/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/gfx.h
Normal file
72
eeshow/gfx/gfx.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* gfx/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_GFX_H
|
||||
#define GFX_GFX_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gfx/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_GFX_H */
|
||||
342
eeshow/gfx/record.c
Normal file
342
eeshow/gfx/record.c
Normal file
@@ -0,0 +1,342 @@
|
||||
/*
|
||||
* gfx/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 "gfx/style.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/text.h"
|
||||
#include "gfx/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/gfx/record.h
Normal file
58
eeshow/gfx/record.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* gfx/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 GFX_RECORD_H
|
||||
#define GFX_RECORD_H
|
||||
|
||||
#include "gfx/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 /* !GFX_RECORD_H */
|
||||
47
eeshow/gfx/style.c
Normal file
47
eeshow/gfx/style.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* gfx/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 "util.h"
|
||||
#include "gfx/style.h"
|
||||
|
||||
|
||||
uint32_t color_rgb[] = {
|
||||
[COLOR_BLACK] = 0x000000,
|
||||
[COLOR_BLUE] = 0x0000ff,
|
||||
[COLOR_GREEN] = 0x00ff00,
|
||||
[COLOR_RED] = 0xff0000,
|
||||
[COLOR_YELLOW] = 0xffff00,
|
||||
[COLOR_WHITE] = 0xffffff,
|
||||
[COLOR_GREEN4] = 0x009000,
|
||||
[COLOR_GREEN3] = 0x00b000,
|
||||
[COLOR_GREEN2] = 0x00d000,
|
||||
[COLOR_CYAN4] = 0x009090,
|
||||
[COLOR_CYAN3] = 0x00b0b0,
|
||||
[COLOR_RED4] = 0x900000,
|
||||
[COLOR_RED3] = 0xb00000,
|
||||
[COLOR_MAGENTA4] = 0x900090,
|
||||
[COLOR_BROWN2] = 0xc06000,
|
||||
[COLOR_PINK4] = 0xff8080,
|
||||
|
||||
/* user-defined colors */
|
||||
[COLOR_DARK_YELLOW] = 0x848400,
|
||||
[COLOR_LIGHT_GREY] = 0xd0d0d0,
|
||||
[COLOR_LIGHT_YELLOW] = 0xffffc2,
|
||||
/*
|
||||
* If COLOR_LIGHT_YELLOW should be visible in diff (and not
|
||||
* just appear white), use 0xffffa0 or darker.
|
||||
*/
|
||||
};
|
||||
|
||||
unsigned n_color_rgb = ARRAY_ELEMENTS(color_rgb);
|
||||
103
eeshow/gfx/style.h
Normal file
103
eeshow/gfx/style.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* gfx/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 GFX_STYLE_H
|
||||
#define GFX_STYLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* FIG colors */
|
||||
|
||||
#define COLOR_NONE -1
|
||||
#define COLOR_BLACK 0
|
||||
#define COLOR_BLUE 1
|
||||
#define COLOR_GREEN 2
|
||||
#define COLOR_RED 4
|
||||
#define COLOR_YELLOW 6
|
||||
#define COLOR_WHITE 7
|
||||
#define COLOR_GREEN4 12
|
||||
#define COLOR_GREEN3 13
|
||||
#define COLOR_GREEN2 14
|
||||
#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_PINK4 27
|
||||
|
||||
#define COLOR_DARK_YELLOW 32 /* user-defined */
|
||||
#define COLOR_LIGHT_GREY 33 /* user-defined, not used by FIG */
|
||||
#define COLOR_LIGHT_YELLOW 34 /* user-defined */
|
||||
|
||||
#define COLOR_COMP_DWG COLOR_RED4
|
||||
#define COLOR_COMP_DWG_BG COLOR_LIGHT_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 COLOR_MISSING_FG COLOR_RED
|
||||
#define COLOR_MISSING_BG COLOR_PINK4
|
||||
|
||||
#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
|
||||
|
||||
#define MISSING_WIDTH 300 // size of missing things indicator box
|
||||
#define MISSING_HEIGHT 300
|
||||
|
||||
extern uint32_t color_rgb[];
|
||||
extern unsigned n_color_rgb;
|
||||
|
||||
#endif /* !GFX_STYLE_H */
|
||||
164
eeshow/gfx/text.c
Normal file
164
eeshow/gfx/text.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* gfx/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 "gfx/style.h"
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/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;
|
||||
unsigned multiline = 0;
|
||||
|
||||
for (s = txt->s; *s; s++)
|
||||
if (*s == '\n')
|
||||
multiline += NEWLINE_SKIP * txt->size;
|
||||
x += rx(0, align(txt->size + multiline, txt->vert) - multiline,
|
||||
txt->rot);
|
||||
y += ry(0, align(txt->size + multiline, txt->vert) - multiline,
|
||||
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;
|
||||
}
|
||||
59
eeshow/gfx/text.h
Normal file
59
eeshow/gfx/text.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* gfx/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 GFX_TEXT_H
|
||||
#define GFX_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,
|
||||
text_italic,
|
||||
};
|
||||
|
||||
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 /* !GFX_TEXT_H */
|
||||
Reference in New Issue
Block a user